类型的运算结果都可以用接口来表示 —— type 声明才是万能的
重载的简写
1 | const is: { |
泛型中 extends 的约束
1 | type MyPick<T, K extends keyof T> = { |
需要注意的是 K 是一个 union,keyof T 也将 T 中的属性转换为一个 union。当我们使用 extends 来进行条件约束的时候,TS 会使用 union 分发 的特性自动遍历 union K 中的属性与 keyof T 中的属性进行比较。
假设 K 为 ‘title’ | ‘completed’ | ‘invalid’ ,T 为 ‘title’ | ‘completed’ | ‘description’。它的过程如下
1 | step1: 'title' extends 'title' | 'completed' | 'description' //通过 |
如果比较成功则通过,失败则报错,这样我们就实现了所有的关键步骤,通过了所有的测试用例。
keyof any
Record<K, V>
1 | type MyRecord<K extends keyof any, V> = { |
注意对象的键值只能是 number | string | symbol ,所以 K 需要被约束
同时,可以使用 keyof any 来代替 number | string | symbol ,它返回对象键值类型的所有可能
接口或者枚举类型中的 never
Omit<T, K>
使用 as never 来使一个元素消失。
在 TS 中如果一个 union 中的元素是一个 never 类型的,那么 TS 认为这个元素是一个空值,会返回去除这个值之后的结果。
infer 的使用
Parameters< T >
在这个条件语句 T extends (...args: infer P) => any ? P : T 中,infer P 表示待推断的函数参数。
整句含义为:如果 T 能赋值给 (...args: infer P) => any,则结果是 (...args: infer P) => any 类型中的参数 P,否则返回为 T
infer 的作用:在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用
1 | type MyParameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never; |
以上代码中 infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用。
类中构造器的类型声明方式
ConstructorParameters< T >
c:{ new(): T } 和 c: new () => T 是一样的,后者是前者的简写,意即 C 的类型是对象类型且这个对象包含返回类型是 T(类的实例) 的构造函数
1 | // es6, T === new People() |
字符串字面量和递归
看到递归的时候,才真正意识到 ts 也是一门编程语言,而不是什么类型的银弹(silver bullet)
1 | type LastChar<T extends string> = |
元祖类型的属性 length
LengthOfTuple< T >
1 | type LengthOfTuple<T extends any[]> = T['length'] |
关于 T extends ${infer L}.${infer R}
如果 T extends 字面量,则 R 表示剩余参数
如果 T extends 元祖,则 R 表示第二个参数
关于 Record<string, unknown>
implement IsEmptyType< T >
Record<string, unknown> 表示任意对象类型
1 | // 首先判断是不是对象类型 |
any类型如何表示
implement IsAny< T >
1 | // 想写出这道题必须了解:any 类型在和其他类型进行联合、交叉时等于 any 类型自身 |
