How to Use Axios Interceptor in TypeScript

mrcaidev

Yuwang Cai

Posted on November 17, 2022

How to Use Axios Interceptor in TypeScript

It's a common practice to retrieve res.data in an Axios response interceptor, but TypeScript knows nothing about it. How can we inform the type system?

πŸ€” Problem

If we don't add a response interceptor, Axios will return such an object rather than the actual data:

{
  "data": {
    // Actual data
  },
  "status": 200,
  "statusText": "OK",
  "headers": {
    // Response headers
  },
  "config": {
    // Axios configuration
  },
  "request": {
    // Request details
  }
}
Enter fullscreen mode Exit fullscreen mode

So it's a common practice to add a response interceptor:

const axiosInstance = axios.create();
axiosInstance.interceptors.response.use((res) => res.data);
const res = await axiosInstance.get("/api");
Enter fullscreen mode Exit fullscreen mode

Thus, the res variable on the final line will be the actual data, saving the trouble of retrieving res.data every time.

But the problem is that TypeScript is not able to detect this interception. In the example above, although we actually get res of type T, TypeScript still assumes res to be of type AxiosResponse<T, any>.

πŸ’‘ Solution

Coming from Axios repository's issues #1510.

We can override Axios' native type declaration by manually creating a .d.ts file:

// src/types/index.d.ts
import axios from "axios";

declare module "axios" {
  export interface AxiosInstance {
    request<T = any>(config: AxiosRequestConfig): Promise<T>;
    get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
    delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
    head<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
    post<T = any>(
      url: string,
      data?: any,
      config?: AxiosRequestConfig
    ): Promise<T>;
    put<T = any>(
      url: string,
      data?: any,
      config?: AxiosRequestConfig
    ): Promise<T>;
    patch<T = any>(
      url: string,
      data?: any,
      config?: AxiosRequestConfig
    ): Promise<T>;
  }
}
Enter fullscreen mode Exit fullscreen mode

And notify TypeScript of this change in tsconfig.json:

// tsconfig.json
{
  // ...
  "typeRoots": ["node_modules/@types", "src/types"]
}
Enter fullscreen mode Exit fullscreen mode

We can find the definition of typeRoots on their official documentation, which is a list of the directories containing all type declarations. In this example, we specify two directories, so TypeScript will look for the definitions of unknown types under these two directories.

The first directory, node_modules/@types comes from Definitely Typed, which contains common types like @types/node.

The second one is our custom type directory. So the next time TypeScript comes across Axios API, it will first find declarations here. Now, TypeScript knows res is of type T.

πŸ’– πŸ’ͺ πŸ™… 🚩
mrcaidev
Yuwang Cai

Posted on November 17, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related