vue3中使用ts给axios接口返回数据和传入参数约束类型

前言

从vue3出来后,使用率越来越高,同时由于vue3由ts编写,对ts支持非常好

越来越多人全面拥抱 vue3+ts 的组合

那么既然用到了ts,肯定就要用好,而不是把它当成 anyScript 来使用,那样就失去了ts的使用意义了

写ts的时候,由于各种类型限制,写起来是比较繁琐的

尤其是当我们在使用 axios 的时候,我们前端本地自己写的可以限制类型

那使用接口后返回的数据该怎么定义约束这些类型呢,让我们的项目更加规范

正文

实际上在axios中也是支持ts的,让我们把它提供的类型进行结合起来

这里我把我的实现思路代码以及注释贴出,以供参考

我们需要思考并实现这几个点

  • 1、如何在请求拦截器的 请求头 上加上我们的 token类型,避免ts类型报错
  • 2、怎么在接口返回数据时约束类型
  • 3、怎么在调用接口时约束入参类型

首先我们按照正常项目思路,创建好我们的axios实例封装文件,在这里定义好相关的类型约束

创建一个 request.ts 文件并创建实例

import axios from 'axios'
​



/* 创建请求实例 */
const service = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com',
  timeout: 30000
})

然后我们需要改装一下axios自带的类型,并重新自定义为我们需要的类型

这里发现自定义的 RequestConfig 参数类型由于是在调用接口实例时使用的,所以headers非必传项

但是在拦截器器中返回的类型出了问题,请求拦截器中的参数必有 headers 字段,所以这里只能分开写成两个

// 引入 axios自带的 请求接口request参数类型 以及 请求接口headers头参数类型
import type { AxiosRequestConfig, AxiosRequestHeaders } from 'axios'
​
// 1、自定义请求接口headers头参数类型
type RequestHeader = AxiosRequestHeaders & { token?: string }
​


// 2、自定义请求接口request参数类型,可以加一些自己自定义的参数
interface RequestConfig extends AxiosRequestConfig {
  headers?: RequestHeader // 放入请求头
  noNeedToken?: boolean // 该接口是否需要token
}

interface RequestInterceptorsConfig extends RequestConfig { // 请求拦截器使用
  headers: RequestHeader;
}

然后在请求拦截器里就可以把相关的自定义参数写上去了

/* 添加请求拦截器 */
service.interceptors.request.use(
  (config: RequestInterceptorsConfig) => { // 请求拦截
    if (config.noNeedToken) { // 自定义的参数,是否不需要token的接口
      return config
    }
    const token = 'aaaaa' // 这里获取token
    if (!token) {
      return Promise.reject();
    }
    if (token) {
      config.headers.token = token // 请求头中添加token
    }
    return config
  },
  (error: AxiosError) => { // 请求错误拦截
    return Promise.reject(error);
  }
);

ts的提示出现了,类型检查生效

image-20230517111437341.png

接下来封装 request请求方法 ,约束接口返回数据类型,使用前面定义好的请求接口RequestConfig 类型

/* 封装实例的请求方法 */
​



// 传入泛型约束返回数据类型
// ApiResponse 主体后端返回格式
interface ApiResponse<T = any> {
  code: number;
  msg: string;
  data: T; // 这里定义请求返回data数据类型
}
export default async function request<T>(config: RequestConfig) {
  // axios实例的 request 接受的第一个泛型参数,就是返回数据data的类型
  return service.request<ApiResponse<T>>(config).then((res) => res.data); // 返回axios的里data数据
}

这里的 ApiResponse 类型是在一般情况下,我们请求后回来的data数据还会再包裹一层后端定义的状态码、消息、数据,这才是我们需要的,所以也要加上类型

image-20230517105019125-1684291828815-1.png

总算配置好了

接下来在scr下新建api文件夹,创建接口文件,引入这个axios实例并使用,直接在request方法传入后端返回的数据格式即可

import request from "../utils/request";

​



interface testModel {

  name: string

  age: number

}

export function test() {
  return request<testModel>({
    method: 'get',
    url: '/test',
  })
}

image-20230517115927464.png

image-20230517115943415.png

ts的提示出现了,类型检查生效

以后只需要根据后端接口文档定义好相应的返回数据类型,然后泛型传入quest方法即可

那么怎么约束入参类型呢,只需要在方法入口处限制即可

参数不对就会提示

image-20230517120318441.png

配置完成!

下面贴上完整代码

代码

文件根目录/types/axios.d.ts

import type {
  AxiosRequestConfig,
  AxiosRequestHeaders,
  AxiosError,
} from "axios";
​


// 自定义请求接口headers头参数类型
type RequestHeader = AxiosRequestHeaders & { token?: string }
​
// 自定义请求接口request参数类型,可以加一些自己自定义的参数
export interface RequestConfig extends AxiosRequestConfig {
  headers?: RequestHeader // 放入请求头
  noNeedToken?: boolean // 该接口是否需要token
}

export interface RequestInterceptorsConfig extends RequestConfig { // 请求拦截器使用
  headers: RequestHeader;
}
​
// 主体后端返回格式
export interface ApiResponse<T = any> {
  code: number;
  msg: string;
  data: T; // 这里定义请求返回data数据类型
}

文件根目录/src/utils/request.ts

import axios from "axios";
import type {
  AxiosError,
} from "axios";
import type { RequestConfig, RequestInterceptorsConfig, ApiResponse } from '../../types/axios'
​


​

/* 创建请求实例 */
const service = axios.create({
  baseURL: "xxxxxxxx",
  timeout: 30000,
});
​
/* 添加请求拦截器 */
service.interceptors.request.use(
  (config: RequestInterceptorsConfig) => { // 请求拦截
    if (config.noNeedToken) { // 自定义的参数,是否不需要token的接口
      return config
    }
    const token = 'aaaaa' // 这里获取token
    if (!token) {
      return Promise.reject();
    }
    if (token) {
      config.headers.token = token
    }
    return config
  },
  (error: AxiosError) => { // 请求错误拦截
    return Promise.reject(error);
  }
);
/* 添加响应拦截器 */
service.interceptors.response.use();
​
​
/* 封装实例的请求方法 */
export default async function request<T>(config: RequestConfig) {
  // axios实例的 request 接受的第一个泛型参数,就是返回数据data的类型
  return service.request<ApiResponse<T>>(config).then((res) => res.data); // 返回axios的里data数据
}
​
​

文件根目录/src/api/user.ts

import request from "../utils/request";

​



interface testModel {

  name: string

  age: number

}

​

interface dataModel { // 接口入参类型
  page: number
  size: number
}

​
export function test(data: dataModel) {
  return request<testModel>({
    method: 'get',
    url: '/test',
    data
  })
}
​
test({page: 1, size: 10}).then(res => {
  console.log(res)
})

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYPrLWxS' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片