typescript axios 使用拦截器时封装通用返回值的方法

最近起的Vue新项目中用到了typescript和axios,并且axios中使用了响应拦截器:

1
2
3
4
5
6
7
8
service.interceptors.response.use(
(response: AxiosResponse) => {
return response.data;
},
(error: any) => {
return Promise.reject(error);
}
)

但是调用时发现返回值仍然是AxiosResponse<any>,这就导致如果在then里做一些关于res的判断时ts会报错:

1
2
3
4
5
6
7
this.$fetch
.get(url, params)
.then((res) => {
if (res.someKey === 0) { // Property 'someKey' does not exist on type 'AxiosResponse<any>'
// do something
}
})

经过一番Google后,终于找到了解决办法:新建一个shims-ajax.d.ts(不一定非要是这个名,任意的*.d.ts都可以)文件,重新声明axios模块,然后在调用时加上泛型,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
declare module 'axios' {
export interface AxiosInstance {
<T = any>(config: AxiosRequestConfig): Promise<T>;
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>;
}
}

interface Data {
someKey: number;
code: number;
errorStr: string;
data: any;
}
this.$fetch
.get<Data>(url, params)
.then((res) => {
if (res.someKey === 0) {
// do something
}
})

到这里问题只解决了一半。因为现在大部分项目后端都会返回本次操作的错误码、错误信息(如果有)、业务数据,如果在每个接口返回值里都声明一次就有点冗余,所以得想办法搞成通用的。我是声明了一个命名空间来解决的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
declare global {
namespace Ajax {
interface Response<T = any> {
someKey: number;
code: number;
errorStr: string;
data: T;
}
}
}

// 调用时
interface Data {
k1: string;
k2: number;
}
this.$fetch.get<Ajax.Response<Data>>(url, params).then((res) => {}).catch(() => {});

这样就不用写那么多冗余的返回值了,美滋滋😋