持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
Extract- 源码
通过源码,咱们很明显就能看出type Extract<T, U> = T extends U ? T : neverExtarct是来判断T类型是否为U类型的‘子类型’或者‘子集’,如果是则返回最终类型T,不是则返回最终类型never。下面通过示例了解Extarct的用法以及更加深入了解extends泛型约束。 - 示例
- 父子类使用
Extarct,这里仅仅展示了接口的情况,类、类型也是一样,这里就不再赘述了。interface People { name: string } // 情况1 interface Men extends People { age: number } // 情况2 interface Men { name: string age: number } // 类型为Men, 情况一二结果一致,这就是上述的子类型或子集 type obj = Extract<Men, People> // 类型为nerve type Example = Extract<string, People> - 联合类型
上面例子,一看是看// string type unionExtract1 = Extract<string, string | number | symbol> // string type unionExtract2 = Extract<string | number, string>unionExtract1为string不少人会感觉很如我所料。但是unionExtract2为string就懵了,这是为啥? 这是TypeScript的检测机制,对于联合类型采用的是一一比对的策略。unionExtract2的生成过程如下: 第一次:拿出前string与后string进行Extract,返回的类型为string; 第二次:拿出前number与后string进行Extract,返回的类型为never; 将两次生成的类型进行联合就返回了结果string | never,never表示什么都没有,但是这里返回的类型可能为string,所以never的存在不成立,因而最终结果为string。 - 函数
对于函数类型来说,判断是否是子类型,有三个方面type func1 = (parame1: 'zhangsan', parame2: number) => string; type func2 = (parame1: string) => 'zhangsan'; // never type funcExtract1 = Extract<func1, func2>; // (parame1: string) => 'zhangsan' type funcExtract2 = Extract<func2, func1>- 返回值类型,子类型的返回值类型必须为父类型的返回值类型的‘子集’
- 参数类型,子类型的参数个数不多于父类型的参数个数。
- 对应位置的参数类型,父类型的对应位置的参数类型必须为子类型的对应位置的参数类型‘子集’;
- 父子类使用
- 源码
Exclude- 源码
通过源码,咱们很明显就能看出type Exclude<T, U> = T extends U ? never : TExclude和Extract正好相反 - 示例
interface Student { name: string, age: number, } interface Teacher { name: string, age: number, salary: number } // 获取Teacher接口中的特有key // "salary" type TeacherPeculiarType = Exclude<keyof Teacher, keyof Student>
- 源码
Record- 源码
源码中有挺多陌生的点,下面就分点解释:type Record<K extends keyof any, T> = { [P in K]: T; }; K extends keyof T,可以判断对象类型或接口T中是否有K属性,如下interface Student { name: string, age: number, } // T[k]就如同获取对象属性一样,不过这里获取的是接口T中K属性的类型 type OneType<T, K> = K extends keyof T ? T[K] : never; // string type StudentOne = OneType<Student, 'name'>K extends keyof T这个的用法懂了,那么源码中的K extends keyof any又是啥东西呢?TypeScript中规定keyof any返回联合类型string | number | symbolK extends keyof any相当于K extends keyof string | number | symbol
在Record中起到约束泛型,确保是有效的key// string | number | symbol type AnyKeyType = = keyof anyP in K,这里的in和Js中的forin有一丢丢相似,都有迭代的意思,具体看示例:in后面的类型范围必须在string | number | symbol之内。- 当
in后面的类型范围为具体字符串时,会根据所有的字符串迭代,并作为key名type InTestType = { [p in 'age']: string } //上述类型相当于 type InTestType = { age: string; } type InTestType2 = { [p in 'age' | 'name']: string } //上述类型相当于 type InTestType = { age: string; name: string } - 当
in后面的类型为string, 相当于只要键名为字符串就可以,对具体键名无要求type InTestType = { [p in string]: string } // 相当于 type InTestType = { [x: string]: string; } - 当
in后面的类型为string | number | symbol,这三个类型单个/成双/成三联合时type InTestType = { [p in symbol | string]: string; } // 相当于 type InTestType = { [x: string]: string; [x: symbol]: string; } - 当
in后面的类型为number, 相当于只要键名为数字就可以,对具体键名无要求。可以表示数组类型type InTestType = { [p in number]: string } // 相当于 type InTestType = { [x: number]: string; } // 正确 let inTest: InTestType = { 0.1: '123' } // 正确 let inArrayTest: InTestType = ['fsdf', 'dsfsdf', 'sdfdsf']
- 当
- 示例
interface ProductType { id: number, [x: string]: any } function arrayToObj<T extends ProductType>(arr: T[]): Record<number, T> { const res: Record<number, T> = {}; arr.forEach(item => { res[item.id] = item }) return res; } interface GoodsType { id: number, name: string, price: number } const goods: GoodsType[] = [ { id: 102, name: 'dfas', price: 13 }, { id: 108, name: 'dsa', price: 15 } ] // 输出 // { // '102': { id: 102, name: 'dfas', price: 13 }, // '108': { id: 108, name: 'dsa', price: 15 } // } console.log(arrayToObj<GoodsType>(goods));
- 源码