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
}
}
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");
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>;
}
}
And notify TypeScript of this change in tsconfig.json
:
// tsconfig.json
{
// ...
"typeRoots": ["node_modules/@types", "src/types"]
}
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
.
Top comments (0)