What is the correct way to incorporate a callback type with parameters into TypeScript?

Here is an example of a method:

export default class ApiService {
  static makeApiCall = (
    url: string,
    normalizeCallback: (data: ResponseData) => ResponseData | null,
    callback: (data: any) => any
  ): Promise<void> => (
    ApiClient.get(url)
      .then(response => {
        callback(normalizeCallback(response.data));
      })
      .catch(error => {
        console.error(`ApiClient ${url}`, error);
      })
  )

  static getArticles = (callback: (articles: Article[]) => void): Promise<void> => (
    ApiService.makeApiCall(
      'articles',
      ApiNormalizer.normalizeArticles,
      callback
    )
  )
}

The line causing a warning in TypeScript is callback: (data: any) => any

warning Unexpected any. Specify a different type

To provide more context, here is how the method getArticles is being called

export const fetchArticles = (): ThunkAction<Promise<void>,{},{},AnyAction> => {
  return async (dispatch: ThunkDispatch<{}, {}, AnyAction>): Promise<void> => {
    dispatch(() => ({ type: FETCH_ARTICLES }));
             // HERE: getArticles
    return ApiService.getArticles(articles => dispatch(loadArticles(articles)));
  };
};

How do I properly type the callback function in this scenario?

Answer №1

I would rewrite it like this:

function createApi<T>(endpoint: string, transformData: (d: ResponseData) => T | null) {
  return function(callback: (data: T | null) => any) {
    return ApiClient.fetch(endpoint)
      .then(res => {
        callback(transformData(res.data));
      })
      .catch(error => {
        console.error(`Error in fetching data from ${endpoint}`, error);
      });
  };
}

// Usage inside a module
const getMovies = createApi<Movie[]>("movies", DataTransformer.normalizeMovies)

This approach ensures:

1) Proper typing with generics for a flexible implementation.

2) Reduction of redundant code and improved readability.

3) Enforcing the encapsulation of createApi within the module instead of exposing it through the class.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

CKEditor4 plugins do not function properly when used with multiple instances within Vue Components

After developing a Vue component for rich text editing with CKEditor 4 on my website, I encountered an issue. When the component is first mounted, everything works perfectly including all default plugins. However, if another instance of the same component ...

Nested Tagged Union Types in Typescript

Imagine having the following types (syntax similar to Elm/Haskell): type Reply = LoginReply | LogoutReply type LoginReply = LoginSucceeded | AlreadyLoggedIn String When trying to represent this in Typescript using discriminated unions, a challenge arises ...

Exploring the World of ESLint, Prettier, Typescript, and VScode Configuration

There is a common belief that Prettier is the preferred tool for formatting, while ESlint is recommended for highlighting linting errors, even though ESlint also has formatting capabilities. However, it should be noted that Prettier lacks certain advanced ...

Transform HTML and CSS into a PDF format using JavaScript

I have a design page in a .cshtml document that displays correctly in all major browsers (FireFox, Chrome, and IE). It utilizes basic CSS for styling and looks great in HTML format. Now, I am attempting to convert one of its DIV elements to PDF. However, ...

Use JQuery version 1.8 or above to link the mousewheel

Currently, my website is utilizing Jquery 1.8.3. Unfortunately, I am facing an issue where I am unable to bind the mousewheel with this version of jQuery, while the 1.4.2 version successfully binds the mousewheel. I am seeking a solution to overcome this ...

The functionality of the Drawer component in material-ui v1.0 seems to be incompatible with TypeScript

Every time I try to utilize Drawer from [email protected] using typescript, I encounter the following error: TS2322: Type '{ children: Element; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes & Re ...

Retrieving data from an API using VUEJS3 and Typescript

I am facing an issue with displaying data in my template. When I try to do so, the screen remains blank. I am using Vue.js 3 with TypeScript and I am fairly new to this technology. <template> <div> <img :src="datas[0].imag ...

Tips for implementing Root Import in React Testing Library for React applications

Whenever I bring my components or pages into my testing file ".spec.tsx", it doesn't seem to recognize Babel Root Import. https://i.sstatic.net/exuKl.png Is there a way to configure my ".spec.tsx" file to acknowledge "~" as the Root Import? The Fou ...

Creating a 3D Slicing Tool using Javascript and Three.js

I am currently working on a web application that utilizes three.js to estimate the cost of a 3D printing model, along with other functionalities. After successfully calculating the bounding box and volume of the object, I am now focusing on generating sli ...

Incorporate a variable within the ng-repeat loop

I need help figuring out how to incorporate my variables into ng-repeat, as shown in the examples below. controller.js $scope.firstParams = $stateParams.firstId; template.html <span style="margin-left:3px;" ng-repeat="list in user.userlists.{{firstP ...

The execution of jQuery was hindered due to the implementation of PHP include

Having an issue with jQuery not working in index.php when including the file header.php. The nav sidebar is included, but clicking the chevron does not trigger anything. It only works when I directly include header_user.php without checking the UserType in ...

Animation not being triggered in Chrome when using the JQuery UI removeClass() method

Hey there stackoverflow community, Edit: I've created a fiddle showcasing the issue area, as requested. Unfortunately, JSfiddle doesn't support JQuery UI animations, so the problem isn't visible there. Check out the JSFiddle here Edit 2: ...

Implementing automatic dark mode activation during nighttime with jQuery or JavaScript

I'm looking to implement an automatic dark mode feature on my website that switches on at night and off during the day or morning. Currently, my website has a dark mode toggle code that allows users to switch between dark and light modes using local ...

Using Angular to make a DELETE request using HttpClient with a Json Server

My goal is to remove one employee at a time from the Employees list. The Observable is configured in employee.service.ts and subscribed in app.component.ts. However, there seems to be an issue connecting the id of the employee with the removeUser(id) metho ...

What is the best way to display the "next" and "previous" buttons for an item in an array?

I am currently attempting to use an array that contains 4 different maps. The initial element of the array should remain constant ("sticked") while the user can cycle through the rest of the elements by clicking the next button. Once the next button reache ...

Utilize Observables to track changes in Ionic 2 form input elements

Is there a way to create an Observable from an Ionic 2 form element without directly accessing the DOM? While the Observable.fromEvent function is useful for events, I have the form element reference from the FormBuilder service, not the actual element it ...

What is the best approach for managing caching effectively?

My SPA application is built using Websocket, Polymer, ES6, and HTML5. It is hosted on a Jetty 9 backend bundled as a runnable JAR with all resources inside. I want to implement a feature where upon deploying a new version of the JAR, I can send a message ...

The nav bar in the React CSS is being populated with elements

Currently, I am in the process of developing a React app that includes a navigation bar. The issue at hand is that the content within my h1 tags and other elements are overlapping with the navigation bar - meaning that they are not properly contained withi ...

Updating the source content of an iframe in real time

Currently, I am working on a search result page. The scenario involves a login page redirecting to a homepage that consists of a dropdown menu, a textbox, a button, and an iframe displaying a table with user data (firstname, lastname, middlename). Upon sel ...

Discover the benefits of utilizing router.back() cascade in Next/React and how to effectively bypass anchor links

Currently, I am working on developing my own blog website using Next.js and MD transcriptions. The issue I am facing involves anchor links. All the titles <h1> are being converted into anchor links through the use of the next Link component: <Link ...