Extracting the function passed into Promise.catch creates a type error

Viewed 95

I'm new to Typescript and am trying to understand a type error. In the code below, which I've simplified, the function ok compiles fine, but when I extract the handleError function out, it no longer type checks. As far as I can tell, the code is identical since all I did was extract a function, but there is obviously something here I don't understand. Can you help me understand why this is happening and if there is a way to fix it?

Here is the code that compiles fine

  const ok = <T>(): Promise<AxiosResponse<T>> =>
    axios.post<T>('http://example.com', {}, {}).catch(
      (params: AxiosError<T>): Promise<AxiosResponse<T>> => {
        return Promise.reject<AxiosResponse<T>>(params)
      }
    )

And here is the code that does not.

  const handleError = <T>(params: AxiosError<T>): Promise<AxiosResponse<T>> => {
    return Promise.reject<AxiosResponse<T>>(params)
  }

  const notOk = <T>(): Promise<AxiosResponse<T>> =>
    axios.post<T>('http://example.com', {}, {}).catch(handleError)

The error I get is

Type 'Promise<AxiosResponse<T> | AxiosResponse<{}>>' is not assignable to type 'Promise<AxiosResponse<T>>'.
  Type 'AxiosResponse<T> | AxiosResponse<{}>' is not assignable to type 'AxiosResponse<T>'.
    Type 'AxiosResponse<{}>' is not assignable to type 'AxiosResponse<T>'.
      Type '{}' is not assignable to type 'T'.  TS2322

    46 | const notOk = <T>(): Promise<AxiosResponse<T>> =>
    47 |   axios.post<T>('http://example.com', {}, {}).catch(handleError)
  > 48 |
       | ^

My guess is that some type information is lost and handleError needs to be told what T is, but I'm not sure how to do that.

Here is a codesandbox in case it helps with inspecting.

1 Answers

Error happens because catch block doesn't substitute generic for your handleError function. To resolve this issue you have to do it manually (example)

export const notOk = <T>(): Promise<AxiosResponse<T>> =>
  axios.post<T>("http://example.com", {}, {}).catch(error => handleError<T>(error));

Another solution is create default generic type for handle error (example)

const handleError = <T = any>(
  params: AxiosError<T>
): Promise<AxiosResponse<T>> => {
  return Promise.reject<AxiosResponse<T>>(params);
};
Related