背景
在上一篇文章中,我们提到了组件参数和函数参数的关联关系。今天来看看另外一个TS类型问题,在编写TS类型时,我们会碰到一些固定格式的数据类型,比较典型的就是分页数据。来看个现状:
我在一个比较新的项目中搜分页入参类型,发现同样的类型,重复定义了4遍。然后想再看看出参的类型是怎么定义的,发现,居然一个都没有。好好好,都搁这偷懒是吧,看返回类型复杂,直接不写了┓( ´∀` )┏
且看我出手整治一下这些“妖魔鬼怪”
自定义工具类型
分页入参
很简单,直接在全局的typings.d.ts声明类型
// typings.d.ts
declare type TRequestPage = {
pageIndex: number;
pageRows: number;
};
但这样有个问题,有筛选条件的话还需要人工拼接,这就不是一个好用的工具类型了
// typings.d.ts
declare type TRequestPage<T = {}> = Partial<T> & {
pageIndex: number;
pageRows: number;
};
定义了一个泛型接收筛选参数,跟分页参数做可选并集。但有部分场景,筛选参数是必传时,这个工具就用不了了,需要再优化一下
// typings.d.ts
declare type TRequestPage<T = {}, K extends keyof T = never> = {
[O in Exclude<keyof T, K>]?: T[O];
} & {
[P in K]: T[P];
} & {
pageIndex: number;
pageRows: number;
};
以上代码做了几个事情:
- 接收了泛型
K,类似与Pick的剩余参数,并设置了默认值never,以适应筛选字段为非必传的场景 - 对泛型
K的参数定义为必传,对T类型下除K泛型之外的参数定义为可选(因为我们业务场景中必传字段相对较少,所以优先默认全部转为可选,再显式传入必传字段,这也是在做工具方法时需要考虑的问题,可选与必传,什么样的场景居多,我们应该开什么样的口子给调用方) - 使用了两个
&符号将可选、必传、默认参数组合在一起,这是type类型限制的,不然类型推导不出来实际所需参数
当然还有一些边界情况我们没有处理:如何限制泛型T传入pageIndex等默认参数且改变了类型,这边就不深入探讨了
再来看看如何使用:
// xxx/types.ts
export type TTrainingOrgForm = {
orgName: string;
orgTypeId: string;
validDay: number;
parentId: number;
}
export type TTrainingOrgListReq = TRequestPage
// or
export type TTrainingOrgListReq = TRequestPage<TTrainingOrgForm>
// or
export type TTrainingOrgListReq = TRequestPage<TTrainingOrgForm,'orgName'>
注:因为我们是在全局类型中使用declare做了类型声明,所以在使用时就无需再引入TRequestPage类型了
分页出参
出参相对来说就比较简单了,因为返回的数据较多且复杂,是否可选的定义则交由使用方定义,工具类型只做标准结构的定义。
// typings.d.ts
declare type TResponsePage<T> = {
list: T[];
total: number;
pageNum: number;
pageSize: number;
size: number;
startRow: number;
endRow: number;
pages: number;
};
使用:
// xxx/types.ts
export type TTrainingOrgList = {
contactName: string;
contactTel: string;
createTime?: string;
createUser?: string;
orgId: number;
orgName: string;
// ....
}
export type TOrgEmployeeListReq = TResponsePage<TTrainingOrgList>
总结
同样的类型写了四遍,而且这么基础的类型也没有提取出来,哪怕封装的没有那么好,要迈出第一步。
现在写了这两个工具类型,但如果不在CR会上同步、检查,就等于白写,沟通很重要!!!
降低开发使用成本,提高技术探索意识