Non
Non

Reputation: 8589

How to add properly to TypeScript a callback type with parameters?

I have this method:

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

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

On this line callback: (d: any) => any typescript yells

warning Unexpected any. Specify a different type

To show you more context, here is where I am calling the method getArticles

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)));
  };
};

So how can i type that callback function properly?

Upvotes: 0

Views: 190

Answers (1)

Jonas Wilms
Jonas Wilms

Reputation: 138407

I'd write it as:

function makeApi<T>(url: string, normalizeCallback: (d: ResponseData) => T | null) {
  return function(callback: (data: T | null) => any) {
    return ApiClient.get(url)
      .then(res => {
        callback(normalizeCallback(res.data));
      })
      .catch(error => {
        console.error(`ApiClient ${url}`, error);
      });
  };
}

// in the class
static getArticles = makeApi<Article[]>("articles", ApiNormalizer.normalizeArticles)

That way, you ...

1) correctly type the data type as a generic.

2) eliminate a lot of boilerplate.

3) enclose makeApi into the module, I don't think it should be exposed through the class.

Upvotes: 1

Related Questions