在ts中为axios添加参数约束和返回值推导

您所在的位置:网站首页 接口返回类型 在ts中为axios添加参数约束和返回值推导

在ts中为axios添加参数约束和返回值推导

2023-04-01 15:34| 来源: 网络整理| 查看: 265

前言

随着vue3的不断推行,越来越多的小伙伴开始加入typescript的怀抱中,开始享受类型化带来的好处。 axios 是常见的ajax库,然而我发现很多小伙伴在使用它的时候打开姿势不太对,导致并没有享受到类型化带来的好处,例如参数字段校验,返回类型自动推导等。 如果你也正在被这些问题困扰的话,那就请继续阅读下去吧。

本文并不会讨论拦截器的相关知识,因为那不是本文的重点。

作者只是一个菜鸟,文中如有错误的地方,欢迎大家指正。

需求

假设我们有一个后端api接口,它就是一个简单的加法接口,接受两个加数,返回一个包含加数以及结果的一个json对象

请求格式 url: '/api/test-plus' methods: 'post' data: {a:2,b:3} 请求成功的返回格式是一个json数据: { code:0, message:"", data:{ a:2, b:3, result:5 } } 复制代码

我们后续的封装都是为了让我们在请求这个接口的时候,代码能推断出返回的结构。

实现参数约束和返回值推导

首先为我们的ts工程参加一个./src/demo.ts文件,并且写一份不带类型参数的代码:

import axios from "axios"; // 创建一个axios实例 const instance = axios.create(); // 通用的请求函数 export async function request(config: any) { return instance.request(config).then((res) => res.data.data); } export async function testApi(data: any) { return request({ url: "/api/test-plus", method: "POST", data: data, }); } // 调用这个接口 testApi({ a: 2 }).then((res) => { console.log(`${res.a} + ${res.b} = ${res.resut}`); }); 复制代码

乍一看,这段代码似乎没有什么问题,但细细看的话,你会发现有两个不足之处:

在最后一行我们调用接口的时候,本来应该传{a:2,b:3},但是我们只传了{a:2},在传给后端以后会报错。 在打印结果的时候,res.resut拼写错误,到运行时的时候会出现 undefined。 细想之下,由于我们没有约定testApi的参数,所以理论上我们无论传什么给testApi都行,同时.then(res) 中,res推断出来的是any类型,导致我们在写形如 res. 这样的代码的时候,编辑器也并不会给我们提示,这样的ts代码简直让人无法接受。

那么我们要该如何约束他们呢?

首先我们约束一下参数:

interface IPlusParams { a: number; b: number; } export async function testApi(data: IPlusParams) { return request({ url: "/api/test-plus", method: "POST", data: data, }); } 复制代码

我们添加了IPlusParams接口,并形参data,这样依赖,typescript就会抱怨调用testApi的时候testApi({ a: 2 })传入的参数不对。

image.png

这就足够了吗? no no no! 我们不仅想约束data的类型,同时我们希望在写

request({ url: "/api/test-plus", method: "POST", data: data, }); 复制代码

这样的代码的时候,我们的编辑器能自动提示,比如我们敲下u,编辑器就给我们提示url。那么要怎么做呢? 很简单,我们为 request函数的参数config添加约束即可。

import axios, { AxiosRequestConfig } from "axios"; // 通用的请求函数 export async function request(config: AxiosRequestConfig) { return instance.request(config).then((res) => res.data.data); } 复制代码

这样一来,我们写配置的时候就会有智能提示了,并且书写错误的时候也会有警告。 image.png image.png

以下是AxiosRequestConfig定义的参考

export interface AxiosRequestConfig { url?: string; method?: Method; baseURL?: string; transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[]; transformResponse?: AxiosResponseTransformer | AxiosResponseTransformer[]; headers?: AxiosRequestHeaders; params?: any; paramsSerializer?: (params: any) => string; data?: D; timeout?: number; timeoutErrorMessage?: string; withCredentials?: boolean; adapter?: AxiosAdapter; auth?: AxiosBasicCredentials; responseType?: ResponseType; xsrfCookieName?: string; xsrfHeaderName?: string; onUploadProgress?: (progressEvent: any) => void; onDownloadProgress?: (progressEvent: any) => void; maxContentLength?: number; validateStatus?: ((status: number) => boolean) | null; maxBodyLength?: number; maxRedirects?: number; socketPath?: string | null; httpAgent?: any; httpsAgent?: any; proxy?: AxiosProxyConfig | false; cancelToken?: CancelToken; decompress?: boolean; transitional?: TransitionalOptions; signal?: AbortSignal; insecureHTTPParser?: boolean; } 复制代码

接下来,我们约束返回值。

interface IPlusParams { a: number; b: number; } interface IPlusReturnValue extends IPlusParams { result: number; } export interface IResponseData { code: number; message: string; data: IPlusReturnValue; } // 通用的请求函数 export async function request(config: AxiosRequestConfig) { return instance.request(config).then((res) => res.data.data); } 复制代码

我们定义一个 IResponseData为axios的数据类型,其中 data字段约束为 IPlusReturnValue。它继承自IPlusParams,然后我们将instance.request的泛型参数约束为IResponseData。这样一来,编译器就能自动推断出 .then((res) => res.data.data);中res.data的类型为IResponseData,res.data.data 的类型为IPlusReturnValue

image.png

image.png

由于函数能自动推导返回值,所以我们的request函数和testApi函数现在能自动推导出返回类型:

image.png

image.png

也就是说,testApi现在能推导出返回值为Promise了。我们在调用testApi函数调时,便可以推导出res形参是IPlusReturnValue类型。

image.png

同时,我们此前出现的拼写错误的bug编译器也给我们识别出来了。到这里我们的已经达成了我们预定的小目标。

编写更通用的request 函数

在上面的代码中我们已经能正确地推断出testApi的参数类型和返回类型了,但是还有改进的地方吗? 答案是有。

export interface IResponseData { code: number; message: string; data: IPlusReturnValue; } 复制代码

目前为止,我们的IResponseData 中的data是写死的IPlusReturnValue类型,这显然是不合理的,我们需要一个更普遍的接口,所以这里我们引入泛型。

export interface IResponseData { code: number; message: string; data: T; } // 改造为泛型接口 export async function request(config: AxiosRequestConfig) { return instance .request(config) // 这里是重点 .then((res) => res.data.data); } // 显式传入泛型参数 IPlusReturnValue export async function testApi(data: IPlusParams) { return request({ url: "/api/test-plus", method: "POST", data: data, }); } 复制代码

我们将IResponseData接口改造成泛型接口,将data的类型改为动态传入,然后将request函数也改造泛型函数,然后在testApi内部,显式传入IPlusReturnValue。这样一来就实现了request函数的通用性改造。

现在,假如我们有一个新的接口,返回一个随机字符串数组

请求格式 url: '/api/test-list' methods: 'get' 请求成功的返回格式是一个json数据,其中data是字符串数组: { code:0, message:"", data:["xxx"] } 复制代码

那么我们只需新增一个接口函数

export async function testApi2() { return request({ url: "/api/test-list", method: "GET", }); } testApi2().then((list) => { list.forEach((a) => console.log(a)); }); 复制代码

编译器能正常地推测出.then(list)中list的类型是string[]。

image.png

到这一步我们就编写了一个更加通用版本的 request 函数。

完整代码 import axios, { AxiosRequestConfig } from "axios"; // 创建一个axios实例 const instance = axios.create(); // 泛型接口,T的类型支持 export interface IResponseData { code: number; message: string; data: T; } // 通用的请求函数 export async function request(config: AxiosRequestConfig) { return instance .request(config) .then((res) => res.data.data); } interface IPlusParams { a: number; b: number; } interface IPlusReturnValue extends IPlusParams { result: number; } export async function testApi(data: IPlusParams) { return request({ url: "/api/test-plus", method: "POST", data: data, }); } // 调用这个接口 testApi({ a: 2, b: 3 }).then((res) => { console.log(`${res.a} + ${res.b} = ${res.result}`); }); export async function testApi2() { return request({ url: "/api/test-list", method: "GET", }); } testApi2().then((list) => { list.forEach((a) => console.log(a)); }); 复制代码 总结

本文通过一个小案例,为封装了一个request函数,使得我们在使用axios能享受到类型编程带来的福利,主要的方法就是利用泛型机制,增加函数的通用性。

作者是一个正在学习ts的菜鸟,本文是我在学习ts的过程中的一点小总结,如果本文有什么错误的地方,欢迎大家指正,如果觉得有帮助的话,记得点个✨ 👍 ✨,谢谢各位!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3