刷完了type-challenges的全部简单和中等难度的标题后,对TypeScript的范例操纵有了一些新的理解和认识。特此用几篇文章来记载下一些重要的知识点。
本系列文章必要您对TypeScript有根本的相识
根本用法
JavaScript通过Object.keys()获取对象的全下属性键值,而typescript重要关注的是范例操纵,通过 keyof 操纵符可以获取对象中的全部键范例构成的团结范例。
为了具体相识keyof操纵符的作用,我们通过一些例子来表明下:
type Person = { id: number; name: string; age: number;};type P1 = keyof Person; //'id' | 'name' | 'age'keyof操纵符得到的是Person范例的全部键值范例即 'id','name'和'age' 三个字面量范例构成的团结范例'id' | 'name' | 'age'。
现实应用
接下来我会用一些例子解说keyof的应用。
获取对象全下属性的范例
type P2 = Person[keyof Person]; // number | string
- Person['key'] 是查询范例(Lookup Types), 可以获取到对应属性范例的范例;
- Person[keyof Person]本质上是实验 Person['id' | 'name' | 'age'];
- 由于团结范例具有分布式的特性,Person['id' | 'name' | 'age'] 酿成了 Person['id'] | Person['name'] | Person['age'];
- 末了得到的效果就是 number | string.
束缚范型参数的范围
type MyPick<T, K extends keyof T> = { [P in K]: T[P] };type P3 = MyPick< erson, 'id' | 'age'>
- K extends keyof T对K举行了束缚,只能是'id','name','age'中的一个范例大概几个范例构成的团结范例;
- 假如没有这个束缚,{ [P in K]: T[P] } 则会报错。
和映射范例组合实现某些功能
type MyReadonly<T> = { readonly [P in keyof T]: T[P] };type P4 = MyReadonly< erson>; // { readonly id: number; readonly name: string; readonly age: number; }
- [P in keyof T]是对全下属性的键值范例举行遍历,案例中得到的P 分别是'id','name'和'age';
- T[P]是查询范例,上面先容过了,Person['id'] 的效果是number,Person['name'] 的效果是string,Person['age'] 的效果是number。
- 将每个属性范例添加readonly修饰符,末了的效果就是 { readonly id: number; readonly name: string; readonly age: number; }
微软官是通过Pick 和exclude组合来实现Omit逻辑的,我们可以通过以下的代码实现同样的功能。
type MyOmit<T, K> = { [P in keyof T as P extends K ? never : P]: T[P] };type P5 = MyOmit< erson, 'id' | 'name'> // {age: number;}代码中的as P extends K ? never : P这部分代码叫做重映射 ,由于我们不肯定必要的是P,有些环境下必要对P举行一些转换;案例中K 中包含的P键值范例则通过never忽略了,相反则生存。所以末了的效果是{age: number;}
type AppendToObject<T, U extends keyof any, V> = {[P in keyof T | U]: P extends keyof T ? T[P] : V}type P6 = AppendToObject< erson, 'address', string> // { address: string; id: number; name: string; age: number; }和条件范例组合实现功能
type Merge<F extends Record<string, any>, S extends Record<string, any>> = { [P in keyof F | keyof S]: P extends keyof S ? S[P] : P extends keyof F ? F[P] : never;};type Skill = { run: () => void;}type P7 = Merge< erson, Skill>; // { id: number; name: string; age: number; run: () => void; }案例中P extends keyof S ? X : Y 的部分叫做 条件范例(背面也会单独先容)。代码中的含义就是假如 P是F的属性范例,则取F[P],假如P是S的属性范例,则取S[P]。
小结
颠末前面的先容,应该对keyof的利用有一些感觉了。下面我列一些代码,各人可以感受下:
type _DeepPartial<T> = { [K in keyof T]?: _DeepPartial<T[K]> }type Diff<T extends Record<string, any>, U extends Record<string, any>> = { [P in keyof U | keyof T as P extends keyof U ? P extends keyof T ? never : P : P extends keyof T ? P : never]: P extends keyof U ? U[P] : P extends keyof T ? T[P] : never;};这个实现逻辑涉及到了其他的知识点有点复杂,没完全看懂没关系,背面会先容。
|