给axios附上体操魔法

本篇章是利用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
相关推荐
派小心.39 分钟前
小程序分享链路中来源参数的传递校验
大数据·前端·数据库·人工智能·小程序·数据分析
hhb_6181 小时前
一键生成数据看板,ECharts实战演示
前端·javascript·echarts
Java后端的Ai之路1 小时前
08_React组件API
前端·react.js·前端框架
小马不起床1 小时前
零基础玩转 FastAPI_09:前端基础工程构建
前端·状态模式·fastapi
风骏时光牛马2 小时前
用户管理模块接口开发
前端
彭亚川Allen3 小时前
从零手搓 RAG 之检索全流程,给大模型接上自己的知识库
前端·后端·ai编程
IT_陈寒3 小时前
别让Java字符串拼接偷偷吃掉你的内存
前端·人工智能·后端
软件技术NINI3 小时前
圣罗兰彩妆html+css 4页
前端·css·html
2601_951615204 小时前
网站模板 网站网页模板下载
前端·网络·html
酷炫码神4 小时前
Day 1|HTML5:一个商城首页的骨架,从 DOCTYPE 到语义化
前端·html·html5