针对基础的Ts知识不做过多解释,相关文档查阅即可.本文注重对于类型操作中的难点和日常项目中的高频类型等做整理.本文会在内置的高级类型基础上延展.
针对内置的高级类型,这里按照操作类型做了简单的分类.
1.函数类
1.Parmeters<T>
1 | /** |
2.ReturnType<T>
1 | /** |
以上两个高级类型中有三个知识点
1. 类型约束 extends
入参部分的T extends (...args: any) => any
用来约束入参的类型为函数类型
2. 条件:extends ? :
类似JS中的三元运算,比如T extends number?true:false
经过计算返回布尔类型,如果T的类型是number则返回true,否则false
3.infer 推导
当在类型计算过程中需要提取其中的类型时,我们可以再适当的位置加 infer
来声明部分类型
2.元组类
1.Exclude<T,U>
1 | /** |
2.Extract<T,U>
1 | /** |
这其中有个重要的知识点就是分布式条件类型,即类型参数为联合类型时,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型.
分布式条件类型条件:
1. 入参为联合类型
2. extends
左边直接对联合类型进行引用 A extends A 是分布式条件类型 ;[A] extends [A] 不是是分布式条件类型
所以再回头分析Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'b'>
,T extends U
右边类型保持不变,将'a' | 'b' | 'c' | 'd'
拆开依次传入,第一次结果'a' extends 'a'|'b'
,结果为never;第二次'b' extends 'a'|'b'
,结果为never;第三次'c' extends 'a'|'b'
,结果为'c'
;第四次'd' extends 'a'|'b'
,结果为'd'
,最后将结果在重新组合成联合类型即'c'|'d'
;
3.索引类型
1.Partial<T>
1 | /** |
2.Required<T>
1 | /** |
3.Readonly<T>
1 | /** |
以上三个类型都用到一个知识点是索引类型的重新构造,索引类型有readonly(只读),?(可选)两种修饰符,这个过程中可以对Value值
和Key值
进行修改,Value值修改直接写入新的类型即可,Key值的修改要用的as,即重映射
下面的例子将Value值类型全部改写为boolean
1 | type Mapping<Obj extends object> = { |
下面的例子是将索引类型的Key大写
因为索引可能是string、number、symbol,而Uppercase只能接受string所以通过交叉类型来限制入参
1 | type UppercaseKey<Obj extends object> = { |
上面三种内置的高级类型具有代表性,其余的比如构造函数和Promise相关的类型可以参考官网文档,因为不具有代表性,不做过得解释.额外添加了几个自定义高级类型,来总结其余的知识点
1.递归循环与模板字面量
CamelCaes<T>
,将连字符字符串转驼峰,比如start_time=>startTime,
1 | type CamelCaes<S extends string> = S extends `${infer First}_${infer Rest}` |
上面的自定义类型用到了两个知识点:模板字面量
和递归循环
模板字面量,类似JS中的语法一样,在合适的位置通过infer声明变量,再通过条件类型提取出来.
下面的例子,我们通过_下划线来构建,左边部分和右边部分,下划线左边部分保持不变,下划线右边部分调用内置类型Capitalize
将首字母大写;但是仅仅这样,如果超过三个以上的单词则无法满足;
1 | type CamelCaes<S extends string> = S extends `${infer First}_${infer Rest}` |
所以对于右边的剩余部分,我们就要采用递归的方法,继续调用;${First}${CamelCaes<Capitalize<Rest>>}
2.模板字面量与联合类型
字符串类型中遇到联合类型的时候,会每个元素单独传入计算,无需再进行递归循环,最典型的例子就是BEM规范
1 | type BEM< |
3.any类型的交叉类型
any 类型与任何类型的交叉都是 any,所以可以用这个特性来判断一个类型是否是any
1 | type IsAny<T> = number extends (number & T) ? true : false |
### 4.any类型作为参数 any 在条件类型中也比较特殊,如果类型参数为 any,会直接返回 trueType 和 falseType 的合并
1 | type TestAny<T> = T extends number ? 1 : 2; |
### 5.元祖类型的length与数组length 元组类型的 length 是数字字面量,而数组的 length 是 number。
1 | type len=[1,2,3]['length] |
### 6.可选索引的索引可能没有,Pick 出来的就可能是 {}
1 | type res = {} extends Pick<{ a?: 1 }, 'a'> ? true : false; |
1 | type GetOptional<Obj extends Record<string, any>> = { |
7.数值计算
这一部分在TS中算是比较难得知识点,核心用法就是利用数组的长度属性来出来.
1 | type res=[1,2,3]['length'] //expected to 3 |
举例求两个数的和
1 | type BuildArray< |
其余的不过多解释,需要了解的请自行搜索
____
思考:过程中发现了这样一个问题,目前还在查阅资料;没想到合理的解释
