Will's blog Will's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • VUE
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

will

前端小学生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • HTML
  • CSS
  • VUE
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 初识 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
上次更新: 2024/08/22, 14:42:43
axios 函数重载
拦截器设计与实现

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

最近更新
01
我用AI写前端代码这一年:从怀疑到真香的转变
09-15
02
基于 Next.js 的无人机数据孪生可视化平台实践
07-17
03
vite 包缓存问题 处理
06-04
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Will | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式