当行动变得无利可图时,收集信息;当信息变得无利可图时,睡觉; ——《黑暗的左手》
接口智能提示
ts
1 | interface Seal { |
高级特性的实际场景应用
泛型使用
ts
1 | type Mode = 'base' | 'same' | 'other' |
多泛型定义和使用
ts
1 | interface Generic<T, U, K> { |
泛型推断 infer
infer的中文是“推断”的意思,一般是搭配上面的泛型条件语句使用的,所谓推断,就是你不用预先指定在泛型列表中,在运行时会自动判断,不过你得先预定义好整体的结构。举个例子
ts
1 | type Foo<T> = T extends {t: infer Test} ? Test: string |
首选看extends后面的内容,{t: infer Test}可以看成是一个包含t属性的类型定义,这个t属性的value类型通过infer进行推断后会赋值给Test类型,如果泛型实际参数符合{t: infer Test}的定义那么返回的就是Test类型,否则默认给缺省的string类型。
ts
1 | type Foo<T> = T extends {t: infer Test} ? Test: string |
infer用来对满足的泛型类型进行子类型的抽取,有很多高级的泛型工具也巧妙的使用了这个方法。
EXtract / Exclude
我们可能想要用在函数里面使用name属性,并透传剩下的属性:
ts
1 | type ExtractName = { |
现在给removeName函数加入类型定义
ts
1 | type ExtractName = { |
上面的例子做了很多事情,它先是继承了Props来包含name属性。然后抽取了name属性,并返回剩下的属性。为了告诉TypeScript函数返回类型的结构,我们移除了ExtractName中的属性(这个例子中的name)。这些工作都是 Pick<Props, Exclude<keyof Props, keyof ExtractName>> 实现的。
重写上面的定义:
ts
1 | type Omit<T, K> = Pick<T, Exclude<keyof T, K>>; |
用Diff函数重写removeName函数:
ts
1 | type Diff<T, K> = Omit<T, keyof K> |
总结来说,Extract
和Exclude
就是这样
ts
1 | type ExtractType<T, U> = T extends U ? T : never // 此时返回的T,是满足原来的T中包含U的部分,可以理解为T和U的交集 |
真正的实际用处都是 返回一个类型的联合子类型,也就是通常是这样
ts
1 | type ExtractUser1 = Extract<'a' | 'b' | 'c', 'a' | 'b'> // 'a' | 'b' |
Records
ts
1 | // Readonly, Partial和 Pick是同态的,但 Record不是。因为 Record并不需要输入类型来拷贝属性,所以它不属于同态: |
高级类型模拟(重点,要考的)
ts
1 | type MockRequired<T> = { |
函数相关的类型
- Parameters
由函数类型的Type的参数类型类型构建一个元组类型 Parameters源码是ts1
2type FillParams = Parameters<typeof Array.prototype.fill> // type FillParams = Parameters<typeof Array.prototype.fill>
type SomeParams = Parameters<typeof Array.prototype.reduce> // type SomeParams = [callbackfn: (previousValue: unknown, currentValue: any, currentIndex: number, array: any[]) => unknown, initialValue: unknown]ts1
2// 此处使用 infer P 将参数定为待推断类型
type Parameters<T extends (...arg: any) => any> = T extends (...args: infer P) => any ? P : never
使用案例
ts
1 | interface IPer { |
- ReturnType
由函数类型Type的返回值类型构建一个新类型 ReturnType主要做的是对函数返回值类型进行构建ts1
2type T1 = ReturnType<() => string>
const test: T1 = 111 // 不能将类型“number”分配给类型“string”RturnType源码是ts1
2
3
4
5type F1 = (args: Generic<string, number, symbol>) => void
const showType: F1 = (args: Generic<string, number, symbol>) => {
console.log('args', args);
}
type ShowFunctionType = ReturnType<F1> // 相等于voidts1
type MockReturnType<T extends (...arg: any) => any> = T extends (...args: any) => infer R ? R : any;
自定义常用类型
- PartialRecord这里出现了一个问题,validateRules 的 key 值必须和 Model 全部匹配,缺一不可,但实际上我们的表单可能只有其中的一两项,这时候我们就需要:ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14interface Model {
name: string;
id: number;
}
type Validator = {
required: boolean;
trigger: string
}
const validateRules: Record<keyof Model, Validator> = {
name: {required: true, trigger: `blur`},
id: {required: true, trigger: `blur`},
email: {required: true, message: `...`},
// error: Property age is missing in type...
}ts1
2
3
4
5type PartialRecord<K extends keyof any, T> = Partial<Records<K, T>>
const validateRuless: PartialRecord<keyof Model, Validator> = {
name: {required: true, trigger: `blur`}
}