本篇章是利用TS的特性去封装axios从而获得魔法般的语法提示。
注意:本篇需要一定的TypeScript基础。
首先我们定义一个Axios类,并且声明私有的axios实例变量,并且在构造函数内赋值给他axios实例,axiosConfig是axios的基本配置参数,实例化Axios时可传过来作为默认配置,如下面代码:
typescript
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
export interface CreateAxiosConfig extends AxiosRequestConfig {
/* 这里定义传递参数类型 */
[key: string]: any // 不确定的话就用这个
}
class Axios<T, TT> {
private axiosInstance: AxiosInstance
constructor(config: CreateAxiosConfig) {
this.axiosInstance = axios.create(config)
}
}
注:CreateAxiosConfig类型继承了原有的请求头类型并且可以自定义请求头传递参数。
紧接着我们新增两个方法,分别叫 interceptorsRequest、interceptorsResponse,他们分别是请求拦截处理方法和响应拦截处理方法,如下面代码:
typescript
private interceptorsRequest() {
this.axiosInstance.interceptors.request
.use(
(config: CreateAxiosConfig) => {
/* 请求拦截处理逻辑 ----- 例子 */
config.headers!['Content-Type'] = 'application/json;charset=UTF-8'
return config
},
(error: Error) => {
return Promise.reject(error)
}
)
}
private interceptorsResponse() {
this.axiosInstance.interceptors.response
.use(
(response: AxiosResponse) => {
/* 响应拦截处理逻辑 */
return response
},
(error: Error) => {
return Promise.reject(error)
}
)
}
注意: 这两方法需要在构造器上初始化调用一下。
紧接着我们新增一个对外暴露的初始化方法,代码如下:
typescript
// TTT为request本身泛型,T,TT则为我们定义的Axios,具体约定为T请求类型,TT为响应类型
request<TTT>(options: T): Promise<TTT> {
return new Promise((resolve, reject) => {
this.axiosInstance.request<TT>(options)
.then((res: AxiosResponse<TT>) => {
resolve((res as any) as Promise<TTT>) // 响应返回Promise
}).catch((e: Error) => {
reject(e)
})
})
}
首先我们看Axios内部的request方法类型,发现他接受三个泛型,第二个为返回类型,但是依赖第一个类型
我们接着看内部的AxiosResponse类型,也发现他接收两个泛型,但是第一个泛型则为响应返回结果的类型,因此,我们只需要定义我们返回类型即可。
OK,接下来我们暴露一个函数,作为实例化我们Axios类,如下代码:
typescript
export interface HeaderResponse { // 自定义响应头类型,可根据自己实际更换
code: number,
message?: String,
data?: any,
[key: string]: any
}
export interface HeaderRequest { // 自定义请求头类型
url: string,
method?: 'post' | 'get' | 'put',
params?: any,
data?: Record<string, any>,
[key: string]: any
}
export type AxiosReturnData<T> = Omit<AxiosResponse, 'data'> & { // 响应结果类型 ---- 可根据自己实际字段更换
data: {
code: string | number,
content: T,
message: string
}
}
function request<T>(options: HeaderRequest): Promise<AxiosReturnData<T>> {
if(!options.method) {
options.method = 'get'
}
return new Axios<HeaderRequest, HeaderResponse>( // 返回初始化的Axios实例
{
timeout: 30000,
withCredentials: true,
baseURL: '/api',
headers: { 'Cache-Control': 'no-cache' }
}
).request<AxiosReturnData<T>>(options)
}
在构造axios实例的时候我们需要定义请求类型和响应类型,泛型参数需要自行定义,以便我们在使用时可以根据不同的请求和响应类型去实例化不同的axios实例。
试验:
typescript
import { request } from "./request"
export const login = <T>(data) => {
return request<T>({
url: `/login`,
method: 'post',
data
})
}
login1<{token: string}>({ // 调用
userCode: 'test',
verCode: '111'
})
.then(res => {
console.log(res.data.content.token)
})
这就拥有很良好的代码提示啦
整体源码
typescript
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
export interface CreateAxiosConfig extends AxiosRequestConfig {
[key: string]: any
}
export interface HeaderResponse {
code: number,
message?: String,
data?: any,
[key: string]: any
}
export interface HeaderRequest {
url: string,
method?: 'post' | 'get' | 'put',
params?: any,
data?: Record<string, any>,
[key: string]: any
}
export type AxiosReturnData<T> = Omit<AxiosResponse, 'data'> & {
data: {
code: string | number,
content: T,
message: string
}
}
class Axios<T, TT> {
private axiosInstance: AxiosInstance
constructor(config: CreateAxiosConfig) {
this.axiosInstance = axios.create(config)
this.initAxios()
}
private initAxios() {
this.interceptorsRequest()
this.interceptorsResponse()
}
private interceptorsRequest() {
this.axiosInstance.interceptors.request
.use(
(config: CreateAxiosConfig) => {
config.headers!['Content-Type'] = 'application/json;charset=UTF-8'
return config
},
(error: Error) => {
return Promise.reject(error)
}
)
}
private interceptorsResponse() {
this.axiosInstance.interceptors.response
.use(
(response: AxiosResponse) => {
return response
},
(error: Error) => {
return Promise.reject(error)
}
)
}
request<TTT>(options: T): Promise<TTT> {
return new Promise((resolve, reject) => {
this.axiosInstance.request<TT>(options)
.then((res: AxiosResponse<TT>) => {
resolve((res as any) as Promise<TTT>)
}).catch((e: Error) => {
reject(e)
})
})
}
}
function request<T>(options: HeaderRequest): Promise<AxiosReturnData<T>> {
if(!options.method) {
options.method = 'get'
}
return new Axios<HeaderRequest, HeaderResponse>(
{
timeout: 30000,
withCredentials: true,
baseURL: '/api',
headers: { 'Cache-Control': 'no-cache' }
}
).request<AxiosReturnData<T>>(options)
}
export default request