
掌握TypeScript的映射类型,了解TypeScript内置的实用类型是如何工作的。
您是否使用过Partial、Required、Readonly和Pick实用程序类型?

你知道他们内部是怎么运作的吗? 如果您想彻底掌握它们并创建自己的实用程序类型,那么不要错过本文所涵盖的内容。
用户注册是日常工作中普遍存在的场景。在这里,我们可以使用TypeScript定义一个User类型,其中所有的键都是必需的。
type User = {name: string;password: string;address: string;phone: string;};
通常,对于注册用户,我们只允许用户修改一些用户信息。此时,我们可以定义一个新的UserPartial类型,它表示要更新的用户对象的类型,其中所有键都是可选的。
type UserPartial = {name?: string;password?: string;address?: string;phone?: string;};
对于查看用户信息的场景,我们希望用户对象对应的对象类型中的所有键都是只读的。对于这个需求,我们可以定义Readonly User类型。
type ReadonlyUser = {readonly name: string;readonly password: string;readonly address: string;readonly phone: string;};
回顾已经定义的三个与用户相关的类型,您将看到它们包含大量重复的代码。


那么我们如何减少上述类型中的重复代码呢? 答案是您可以使用映射类型,这是可用于将原始对象类型映射到新对象类型的泛型类型。

映射到可选属性


映射到只读属性

映射类型的语法如下:

映射类型语法
其中K中的P类似于JavaScript的for. .in语句,用于遍历类型K中的所有类型,以及类型变量T,用于表示TypeScript中的任何类型。

映射类型修饰符
您还可以在映射过程中使用附加的修饰符read-only和问号(?)。通过添加加号()和减号(-)前缀来添加和删除相应的修饰符。默认情况下,如果没有添加前缀,则使用加号。
现在我们可以总结一下常见映射类型的语法。
{ [ P in K ] : T }{ [ P in K ] ?: T }{ [ P in K ] -?: T }{ readonly [ P in K ] : T }{ readonly [ P in K ] ?: T }{ -readonly [ P in K ] ?: T }
在介绍映射类型的语法之后,让我们看一些示例。

让我们看一下如何使用映射类型重新定义UserPartial类型
type MyPartial<T> = {[P in keyof T]?: T[P];};
type UserPartial = MyPartial<User>;
在上面的代码中,我们定义了MyPartial映射类型,然后使用它将User类型映射到UserPartial类型。keyof操作符用于获取类型的所有键,其返回类型为联合类型。类型变量P在每次遍历时变为不同的类型T[P],这与属性访问的语法类似,用于获取与对象类型的属性对应的值的类型。
让我们来演示MyPartial映射类型的完整执行流程,如果你不确定,可以多看几遍,加深对TypeScript映射类型的理解。
MyPartial执行流程:

TypeScript 4.1允许我们使用 as 子句来重新映射映射类型中的键。其语法如下:
type MappedTypeWithNewKeys<T> = {[K in keyof T as NewKeyType]: T[K]// ^^^^^^^^^^^^^// New Syntax!}
其中NewKeyType的类型必须是字符串|数字|符号联合类型的子类型。使用 as 子句,我们可以定义一个Getter实用程序类型,为对象类型生成相应的Getter类型。
type Getters<T> = {[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]};
interface Person {name: string;age: number;location: string;}
type LazyPerson = Getters<Person>;// {// getName: () => string;// getAge: () => number;// getLocation: () => string;// }

在上面的代码中,由于keyof T返回的类型可能包含符号类型,并且Capitalize实用程序类型要求要处理的类型必须是字符串类型的子类型,因此需要使用 & 操作符进行类型过滤。
此外,在重新映射键的过程中,我们可以通过返回 never 类型来过滤键。
// Remove the 'kind' propertytype RemoveKindField<T> = {[K in keyof T as Exclude<K, "kind">]: T[K]};
interface Circle {kind: "circle";radius: number;}
type KindlessCircle = RemoveKindField<Circle>;// type KindlessCircle = {// radius: number;// };

读完这篇文章,我相信你已经理解了映射类型是做什么的,以及TypeScript中的一些实用工具类型是如何实现的。
欢迎关注公众号:文本魔术,了解更多




















