🈲拒绝类型体操,打通TypeScript类型复用的任督二脉

前言

下面以vue3项目实战中的一个例子,带你快速了解在做项目时,如何去封装接口类型,并且说明在页面中存在表单时,该如何去复用已定义的接口类型,避免多次重复定义同一字段类型。其中涉及到ts中的PickOmitPartialPickRequiredRecord几种工具类型用法。

接口响应体封装

后端在设计接口返回值时一般都会封装一个响应体,这个响应体除了返回接口查询的对应数据外,还会包含一些接口请求的额外信息,比如响应状态码响应消息等,我们可根据接口的响应体数据类型,也定义一个响应体接口,在axios请求方法(getpostputdelete)的返回值类型中使用。

axios.ts

// 基础响应体
export interface BasicResResult<T> {
  // 响应消息
  message: string,
  // 响应数据
  payload: T,
  // 响应状态
  success: boolean
}

以上payload为接口返回的数据,由于每个接口返回的数据类型不同,所有把它定义为一个泛型

下面实现一个简单的get请求封装,返回值类型为Promise<BasicResResult<T>>

class HttpRequest {
  // ...
  get<T = any>(url: string, params?: TParams): Promise<BasicResResult<T>> {
    return axios.get(url, { params })
  }
}
export default new HttpRequest()

以上get方法的类型参数T就是我们在调用对应接口时传递的返回数据类型,如以下获取用户方法:

api/subject.ts

import request from '@/utils/request'
import type { ISubject } from '#/subject'
export const getSubjectList = () => {
  return request.get<ISubject[]>('/project/subjects')
}

接口响应数据类型封装

types/subject.ts

最简单的方式就是所有接口类型都根据接口文档中所描述的所有字段都一一列出来定义。

但个人觉得定义一个大部分接口都具有公共字段的基类接口比较好,比如id字段可放到基类接口里,其他接口在定义类型时,就可直接继承这个基类接口。

这样可以避免每个接口都重复定义id字段,如果之后后端要求对每个接口都增加某些字段(如:数据创建时间,修改时间等)时,可直接在基类接口增加即可。

// 公共字段基类接口
interface BasicInterFace {
  id: number,
  createTime: string,
  updateTime: string
}
// 继承基类接口
export interface ISubject extends BasicInterFace {
  name: string,
  code: string,
  siteId: number,
  siteName: string
}
// 当然也不是一定要这样,最好是要有一套属于自己的团队规范。

在对以上接口做好封装后,我们在页面中调用接口时就可获得良好的类型提示:

🈲拒绝类型体操,打通TypeScript类型复用的任督二脉

页面中如何复用接口类型

在我们做后台管理系统时,其实大部分情况下,表单字段的数据类型,都已经在接口的数据响应类型中定义好了,这时我们可以直接通过ts的工具类型(如:Pick,Omit,Partial等)获取表单所需字段即可。

form表单复用接口类型

使用Pick工具类型,截取ISubject接口中的namecodesiteId字段:

type TForm = Pick<ISubject, 'name' | 'code' | 'siteId'>
// 创建受试者表单
const form = ref<TForm>({ name: '', code: '', siteId: 0 })

🈲拒绝类型体操,打通TypeScript类型复用的任督二脉
如果code编码为非必填项,后台可自动生成时,可以使用Partial工具类型转为非必填项,再配合&交叉使用即可:

type TForm = Pick<ISubject, 'name' | 'siteId'> & Partial<Pick<ISubject, 'code'>>
// 创建受试者表单
const form = ref<TForm>({ name: '', siteId: 0 })

form类型如下图所示:

🈲拒绝类型体操,打通TypeScript类型复用的任督二脉

过滤表单复用表单类型

除了创建表单外,我们页面上可能还会有过滤数据的表单,过滤表单中的字段可能都是非必填项,这时我们可以通过Partial转换一下表单类型即可:

// 表单类型
type TForm = Pick<ISubject, 'name' | 'code' | 'siteId'>
// 表单类型转为非必填
type TFilterForm = Partial<TForm>
// 过滤数据表单
const filterForm = ref<TFilterForm>({})

TFilterForm类型如下图所示:

🈲拒绝类型体操,打通TypeScript类型复用的任督二脉

如果接口不支持表单中的code字段查询,其他都支持,可通过Omit来排除该字段即可:

// 排除表单类型的code字段,再转为全部非必填
type TFilterForm2 = Partial<Omit<TForm, 'code'>>

TFilterForm2类型如下图所示:

🈲拒绝类型体操,打通TypeScript类型复用的任督二脉

扩展阅读

Partial工具类型有一个相对的工具类型Require,可把非必填项转为必填项:

type TFilterForm3 = Required<TFilterForm2>

TFilterForm2属性全部转为必填项:

🈲拒绝类型体操,打通TypeScript类型复用的任督二脉

如果你需要手动创建具有特定键类型和值类型的对象类型,也可使用Record工具类型:

type TPersion = Record<'name' | 'age', string>
// 等价于
type TPersion2 = {
  name: string,
  age: string
}

注意: 以上interface接口类型和type类型的命名,我都分别使用了IT作为类型名称前缀来规范类型命名,大家也可根据自己的项目实际情况来做类型规范命名。

总结

以上讲解了如何去定义接口类型,并且通过一个页面中表单类型复用接口类型的小例子,讲解了ts中的PickOmitPartialPickRequiredRecord几种工具类型用法,合理去使用它们可以让我们避免去多次重复定义同一字段类型,让你摆脱类型体操的烦恼。

原文链接:https://juejin.cn/post/7349791638111600650 作者:不要止步于此

(0)
上一篇 2024年3月25日 上午10:16
下一篇 2024年3月25日 上午10:27

相关推荐

发表回复

登录后才能评论