0. 系列文章

1.使用Typescript重构axios(一)——写在最前面

2.使用Typescript重构axios(二)——项目起手,跑通流程

3.使用Typescript重构axios(三)——实现基础功能:处理get请求url参数

4.使用Typescript重构axios(四)——实现基础功能:处理post请求参数

5.使用Typescript重构axios(五)——实现基础功能:处理请求的header

6.使用Typescript重构axios(六)——实现基础功能:获取响应数据

7.使用Typescript重构axios(七)——实现基础功能:处理响应header

8.使用Typescript重构axios(八)——实现基础功能:处理响应data

9.使用Typescript重构axios(九)——异常处理:基础版

10.使用Typescript重构axios(十)——异常处理:增强版

11.使用Typescript重构axios(十一)——接口扩展

12.使用Typescript重构axios(十二)——增加参数

13.使用Typescript重构axios(十三)——让响应数据支持泛型

14.使用Typescript重构axios(十四)——实现拦截器

15.使用Typescript重构axios(十五)——默认配置

16.使用Typescript重构axios(十六)——请求和响应数据配置化

17.使用Typescript重构axios(十七)——增加axios.create

18.使用Typescript重构axios(十八)——请求取消功能:总体思路

19.使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式

20.使用Typescript重构axios(二十)——请求取消功能:实现第一种使用方式

21.使用Typescript重构axios(二十一)——请求取消功能:添加axios.isCancel接口

22.使用Typescript重构axios(二十二)——请求取消功能:收尾

23.使用Typescript重构axios(二十三)——添加withCredentials属性

24.使用Typescript重构axios(二十四)——防御XSRF攻击

25.使用Typescript重构axios(二十五)——文件上传下载进度监控

26.使用Typescript重构axios(二十六)——添加HTTP授权auth属性

27.使用Typescript重构axios(二十七)——添加请求状态码合法性校验

28.使用Typescript重构axios(二十八)——自定义序列化请求参数

29.使用Typescript重构axios(二十九)——添加baseURL

30.使用Typescript重构axios(三十)——添加axios.getUri方法

31.使用Typescript重构axios(三十一)——添加axios.all和axios.spread方法

32.使用Typescript重构axios(三十二)——写在最后面(总结)

项目源码请猛戳这里!!!

1. 前言

在大型项目开发中,基于模块化开发的思想,我们往往不会把所有的请求操作直接写入逻辑内,而是将所有的请求按照需求不同分门别类的统一放在一个地方,例如博主在手头的项目开发中,会在项目目录下新建一个叫做api的文件夹,在该文件夹内根据业务模块的不同放置不同的请求文件,例如,关于用户增删改查的请求会在api文件夹内新建一个user.ts文件,然后将四个请求放入该文件;关于日志增删改查的请求会放入log.ts文件中,如下所示:

├── api
├── user.ts // 用户相关的请求
├── log.ts // 日志相关的请求
...

而在每个文件中,也会把每个请求抽离成单独函数导出,供需要的地方调用,如在user.ts中:

// 获取用户
export function getUser() {
return axios.get('/getuser')
.then(res => res.data)
.catch(err => console.error(err))
} // 创建用户
export function createUser(data) {
return axios.post('/createUser',data)
.then(res => res.data)
.catch(err => console.error(err))
} // 删除用户
export function deleteUser() {
return axios.delete('/deleteUser')
.then(res => res.data)
.catch(err => console.error(err))
} // ...

这样做的好处是,所有请求能够被集中统一的管理起来,如果日后有变动也可以快速的找到。

前言说了这么多,还是没有引入正题,其实博主是想说:当我们发出请求后,我们最关心的一个是请求是否成功,另外一个就是返回的响应数据是不是我们想要的,我们能否预先定义一个期望返回的数据类型接口,然后看返回的响应数据能否匹配预先定义的接口,就能够得知返回的数据是不是我们想要的?答案当然是可以的。

2. 需求分析

我们之前给所有的请求响应都规定一个类型接口,我们规定,所有的请求返回的响应都应该包含以上几个部分,如下:

export interface AxiosResponse {
data: any; // 服务端返回的数据
status: number; // HTTP 状态码
statusText: string; // 状态消息
headers: any; // 响应头
config: AxiosRequestConfig; // 请求配置对象
request: any; // 请求的 XMLHttpRequest 对象实例
}

但是仅仅是这样还不够,我们还希望能够细化到返回的数据data上,例如,当我们获取用户时发出getUser请求时,我们希望返回的数据data应该是{name:'难凉热血',age:'18'}这样的,由于每个请求期望返回的data不尽相同,那么我们就应该在发出请求时带上我们想要的data类型接口,当数据data返回时去匹配我们所携带的接口看是否匹配得上,进而确保是我们想要的数据。

那么,这就要求我们上面定义的AxiosResponse接收一个泛型参数,这个参数就是返回数据data参数,如下:

export interface AxiosResponse<T = any> {
data: T; // 服务端返回的数据
status: number; // HTTP 状态码
statusText: string; // 状态消息
headers: any; // 响应头
config: AxiosRequestConfig; // 请求配置对象
request: any; // 请求的 XMLHttpRequest 对象实例
}

这里我们给 AxiosResponse 接口添加了泛型参数 TT=any 表示泛型的类型参数默认值为 any

有了这个泛型参数以后,我们在发送请求时就可以指定返回的data的类型了,如下:

// 获取用户api
export function getUser<T>() {
return axios.get<ResponseData<T>>('/getuser')
.then(res => res.data)
.catch(err => console.error(err))
} // 调用getUser发出请求 // 期望返回data的类型
interface User {
name: string
age: number
} async function test() {
// user 被推断出为
// {
// data: { name: string, age: number },
// ...
// }
const user = await getUser<User>()
}

3. 接口添加泛型参数

接下来,我们就为之前定义好的所有接口都加上泛型参数。

// src/types/index.ts

export interface AxiosPromise<T=any> extends Promise<AxiosResponse<T>> {}

export interface Axios {
request<T=any>(config: AxiosRequestConfig): AxiosPromise<T>; get<T=any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; delete<T=any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; head<T=any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; options<T=any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>; post<T=any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; put<T=any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>; patch<T=any>(url: string, data?: any, config?: AxiosRequestConfig): AxiosPromise<T>;
}
export interface AxiosInstance extends Axios {
<T=any>(config: AxiosRequestConfig): AxiosPromise<T>;
<T=any>(url: string, config?: AxiosRequestConfig): AxiosPromise<T>;
}

我们为 AxiosPromiseAxios 以及 AxiosInstance 接口都加上了泛型参数。我们可以看到这些请求的返回类型都变成了 AxiosPromise<T>,也就是 Promise<AxiosResponse<T>>,这样我们就可以从响应中拿到了类型 T 了。

OK,响应数据的泛型参数就已经添加好了,接下里,就可以编写demo来测试一下效果。

4. demo编写

examples 目录下创建 addGenericityToAxiosResponse目录,在 addGenericityToAxiosResponse目录下创建 index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>addGenericityToAxiosResponse demo</title>
</head>
<body>
<script src="/__build__/addGenericityToAxiosResponse.js"></script>
</body>
</html>

接着再创建 app.ts 作为入口文件:

import axios from "../../src/axios";

interface User {
name: string;
age: number;
} function getUser<T>() {
return axios<T>("/api/getuser")
.then(res => res)
.catch(err => console.error(err));
} async function userList() {
const user = await getUser<User>();
if (user) {
console.log(user.data.name);
}
} userList();

我们看到,在编写代码的时候,TypeScript已经可以帮我们推断出user中我们预先定义好的想要的数据了。

接着在 server/server.js 添加新的接口路由:

// 响应支持泛型
router.get("/api/getuser", function(req, res) {
res.json({
msg: "hello world",
data: { name: "难凉热血", age: 18 }
});
});

最后在根目录下的index.html中加上启动该demo的入口:

<li><a href="examples/addGenericityToAxiosResponse">addGenericityToAxiosResponse</a></li>

OK,我们在命令行中执行:

# 同时开启客户端和服务端
npm run server | npm start

接着我们打开 chrome 浏览器,访问 http://localhost:8000/ 即可访问我们的 demo 了,我们点击 addGenericityToAxiosResponse,通过F12network 部分我们可以看到请求已正常发出:

OK,让响应数据支持泛型就已经实现完毕了。

(完)

使用Typescript重构axios(十三)——让响应数据支持泛型的更多相关文章

  1. 使用Typescript重构axios(六)——实现基础功能:获取响应数据

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  2. 使用Typescript重构axios(十六)——请求和响应数据配置化

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  3. 使用Typescript重构axios(七)——实现基础功能:处理响应header

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  4. 使用Typescript重构axios(八)——实现基础功能:处理响应data

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  5. 使用Typescript重构axios(二十三)——添加withCredentials属性

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  6. 使用Typescript重构axios(一)——写在最前面

    0.系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三)- ...

  7. 使用Typescript重构axios(二)——项目起手,跑通流程

    0.系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三)- ...

  8. 使用Typescript重构axios(三)——实现基础功能:处理get请求url参数

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  9. 使用Typescript重构axios(四)——实现基础功能:处理post请求参数

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

随机推荐

  1. Python 命令行参数解析工具 argparse

    为什么需要argparse 开门见山,举一个简易计算器代码的例子,其中sys.argv用来读取脚本执行时后面传入的参数. def calculator(x, y, operation): if &qu ...

  2. 在Mac上搭建带ssl协议和域名指向的Apache服务器

    顾名思义,就是要在苹果电脑上搭建 Apache 服务器,并且支持 https 协议,能用指定域名访问(有些开发调试需要注册域名,比如调试微信JS-SDK),当然最好能在手机端进行调试.首先,Mac 系 ...

  3. 报错fatal: refusing to merge unrelated histories

    提交到远程仓库的时候报错如下 是因为远程仓库有东西更新,但本地仓库没有更新造成提交失败 需要先把远程仓库给拉取下来,执行命令git pull origin master,又报错了如下 是因为两个仓库提 ...

  4. Spring Boot 定时任务 @Scheduled

    项目开发中经常需要执行一些定时任务,比如在每天凌晨,需要从 implala 数据库拉取产品功能活跃数据,分析处理后存入到 MySQL 数据库中.类似这样的需求还有许多,那么怎么去实现定时任务呢,有以下 ...

  5. Warfare And Logistics UVA - 1416

    题目链接:https://vjudge.net/problem/UVA-1416 题解: 这是一个最短路的好题,首先我们考虑如果暴力弗洛伊德,显然时间复杂度不对,如果做n次spfa好像复杂度也不对,所 ...

  6. SQL SERVER 日志如何进行收缩?

        最近经历了一次服务器SQL SERVER 数据库服务器端事务日志爆满,导致服务器数据库写入不进数据的宕机事件,经过此次事件的发生,奉劝各位同仁一句,如果没有绝对的充足存储空间,数据库事务日志文 ...

  7. Vue-CLI项目vuex仓库

    0901自我总结 Vue-CLI项目vuex仓库 一.概念 vuex仓库是vue全局的数据仓库,好比一个单例,在任何组件中通过this.$store来共享这个仓库中的数据,完成跨组件间的信息交互. v ...

  8. PHP pa和ma

    <?php class Mouse { private $color; public $sex; public function __construct($role){ switch($role ...

  9. Spring Boot入门(一):搭建Spring Boot项目

    从本篇博客开始,我们开始进入Spring Boot的世界,它的出现使Spring的开发变得更加简洁,因此一经推出受到众多程序员的喜爱. 作为Spring Boot系列的第一篇博客,我们先来讲解下如何搭 ...

  10. PHP代码审计基础-高级篇

    高级篇主要讲 1. 熟知各个开源框架历史版本漏洞. 2. 业务逻辑漏洞 3. 多线程引发的漏洞 4. 事务锁引发的漏洞 在高级篇审计中有很多漏洞正常情况下是不存在的只有在特殊情况下才有 PHP常用框架 ...