### 彪哥

爱好前端

- 初识 TypeScript

- TypeScript 常用语法

- ts-axios 项目初始化

- ts-axios 基础功能实现

- ts-axios 异常情况处理

- ts-axios 接口扩展

  - 扩展接口
  - axios 函数重载
  - 响应数据支持泛型
    - 需求分析
    - 接口添加泛型参数
    - demo 编写

- ts-axios 拦截器实现

- ts-axios 配置化实现

- ts-axios 取消功能实现

- ts-axios 更多功能实现

- ts-axios 单元测试

- ts-axios 部署与发布

- 《TypeScript 从零实现 axios》
- ts-axios 接口扩展

HuangYi
2020-01-05
目录

# 响应数据支持泛型

# # 响应数据支持泛型

## # 需求分析

通常情况下，我们会把后端返回数据格式单独放入一个接口中：

    // 请求接口数据
    export interface ResponseData<T = any> {
      /**
       * 状态码
       * @type { number }
       */
      code: number

      /**
       * 数据
       * @type { T }
       */
      result: T

      /**
       * 消息
       * @type { string }
       */
      message: string
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

我们可以把 API 抽离成单独的模块：

    import { ResponseData } from './interface.ts';

    export function getUser<T>() {
      return axios.get<ResponseData<T>>('/somepath')
        .then(res => res.data)
        .catch(err => console.error(err))
    }

1
2
3
4
5
6
7

接着我们写入返回的数据类型 `User`，这可以让 TypeScript 顺利推断出我们想要的类型：

    interface User {
      name: string
      age: number
    }

    async function test() {
      // user 被推断出为
      // {
      //  code: number,
      //  result: { name: string, age: number },
      //  message: string
      // }
      const user = await getUser<User>()
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14

## # 接口添加泛型参数

根据需求分析，我们需要给相关的接口定义添加泛型参数。

`types/index.ts`：

    export interface AxiosResponse<T = any> {
      data: T
      status: number
      statusText: string
      headers: any
      config: AxiosRequestConfig
      request: any
    }

    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>
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

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

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

## # demo 编写

`examples/extend/app.ts`：

    interface ResponseData<T = any> {
      code: number
      result: T
      message: string
    }

    interface User {
      name: string
      age: number
    }

    function getUser<T>() {
      return axios<ResponseData<T>>('/extend/user')
        .then(res => res.data)
        .catch(err => console.error(err))
    }

    async function test() {
      const user = await getUser<User>()
      if (user) {
        console.log(user.result.name)
      }
    }

    test()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

当我们调用 `getUser<User>` 的时候，相当于调用了 `axios<ResponseData<User>>`，也就是我们传入给 `axios` 函数的类型 `T` 为 `ResponseData<User>`；相当于返回值 `AxiosPromise<T>` 的 `T`，实际上也是 `Promise<AxiosResponse<T>>` 中的 `T` 的类型是 `ResponseData<User>`，所以响应数据中的 `data` 类型就是 `ResponseData<User>`，也就是如下数据结构：

    {
      code: number
      result: User
      message: string
    }

1
2
3
4
5

这个也是 `const user = await getUser<User>()` 返回值 `user` 的数据类型，所以 TypeScript 能正确推断出 `user` 的类型。

至此，我们的 `ts-axios` 接口扩展章节就告一段落了，下一章我们来实现 `axios` 的一个非常好用的功能 —— 拦截器。

编辑
(opens new window)
#TypeScript
上次更新: 2022/12/14, 19:36:42
axios 函数重载
拦截器设计与实现

← axios 函数重载 拦截器设计与实现→

最近更新

  01
Git修改分支名
08-11

  02
CSS给table的tbody添加滚动条
06-29

  03
我做了一个手写春联小网页，祝大家虎年暴富 原创
01-28

更多文章>

Copyright © 2016-2022 Hesb | MIT License

- 跟随系统
- 浅色模式
- 深色模式
- 阅读模式