Skip to Content

面试导航 - 程序员面试题库大全 | 前端后端面试真题 | 面试

TypescriptTS 中的映射类型

在 TypeScript 中,映射类型(Mapped Types)是一种通过遍历一个类型的属性并对其进行修改、扩展或生成新类型的强大工具。通过映射类型,你可以基于现有类型动态创建新的类型。

映射类型的基础语法利用了 TypeScript 中的 in 关键字,允许你对类型中的每个属性进行处理和转换。映射类型使你能够灵活地操作对象类型的结构,控制对象的每个属性如何被类型化。

基本语法

映射类型的基本语法如下:

type MappedType<T> = { [P in keyof T]: Type; };

在这个基础语法中:

  • T:是我们要遍历的类型。
  • keyof T:表示类型 T 中所有键的联合类型。keyof T 获取 T 的所有属性名,并将其作为键来进行映射。
  • [P in keyof T]:表示遍历 T 中的每个键 P
  • Type:是每个键对应的新类型。

基本的映射类型

假设我们有一个接口 Person,我们想要遍历这个类型的所有属性,并将所有属性的类型都设为 string

interface Person { name: string; age: number; } type StringifiedPerson = { [P in keyof Person]: string; };

在上面的代码中:

  • keyof Person 会获取 Person 类型中的所有键:"name""age"

  • StringifiedPerson 类型的每个键对应的值都被映射为 string 类型。所以最终的类型 StringifiedPerson 会变成如下图结果所示。

映射类型与可选属性

映射类型还允许我们更灵活地控制属性的可选性、只读性等。你可以使用 ?readonly 来修改属性的特性。

使所有属性变为可选

我们可以使用映射类型和 ? 操作符来使所有属性变为可选:

type OptionalPerson = { [P in keyof Person]?: Person[P]; };

在上面的代码中:

  • [P in keyof Person] 会遍历 Person 类型的所有属性。
  • ? 标记了每个属性为可选属性。
  • Person[P] 保证了每个属性的值类型保持一致。

OptionalPerson 会变成:

使所有属性变为只读

如果我们希望将对象的所有属性变成只读属性,可以使用 readonly

type ReadonlyPerson = { readonly [P in keyof Person]: Person[P]; };

在上面的代码中readonly 修饰符使每个属性成为只读属性。

ReadonlyPerson 类型会变成:

映射类型的条件类型

映射类型还可以与 条件类型 结合使用,创建更加动态和复杂的类型映射。比如,如果你想将所有 number 类型的属性转成 string,而不改变其他类型的属性,你可以使用条件类型来判断每个属性的类型。

type TransformNumbers<T> = { [P in keyof T]: T[P] extends number ? string : T[P]; };

在这个例子中:

  • [P in keyof T] 会遍历 T 类型的每个属性。

  • T[P] extends number ? string : T[P] 是一个条件类型,用来判断属性值类型是否为 number,如果是,转换为 string,否则保持原类型。

应用到 Person 类型

假设我们有以下的 Person 类型:

interface Person { name: string; age: number; isActive: boolean; }

使用 TransformNumbers 类型:

type TransformedPerson = TransformNumbers<Person>;

TransformedPerson 会变成:

这里,age 的类型被转换成了 string,而其他属性(nameisActive)则保持不变。

使用 as 操作符修改键

有时我们需要在映射类型中修改属性的名字,可以通过 as 操作符来实现。例如,将所有属性的键都加上一个前缀:

type PrefixedPerson = { [P in keyof Person as `prefix_${string & P}`]: Person[P]; };

在上面的代码中:

  • as 操作符允许我们通过模板字面量类型修改每个键的名称。

  • string & P 确保 P 是一个字符串。

如下代码所示:

interface Person { name: string; age: number; isActive: boolean; } type PrefixedPerson = { [P in keyof Person as `prefix_${string & P}`]: Person[P]; }; const person: PrefixedPerson = { prefix_name: 'Moment', // 对应原属性 name prefix_age: 30, // 对应原属性 age isActive: true, // 类型错误:对象字面量只能指定已知属性,并且“isActive”不在类型“PrefixedPerson”中。 };

这会将所有属性的名称加上 prefix_,例如:

映射类型与 in 的更多用法

in 关键字在映射类型中的作用是遍历 keyof T 中的每个键来创建新的类型。可以通过以下方式对它进行更复杂的操作:

  • 只选择特定的键:通过条件类型或其他类型操作,来决定哪些键需要被映射或修改。

  • 生成新类型:你可以通过映射类型来生成基于现有类型的全新类型,如创建只包含某些属性的对象类型。

如下代码所示:

type PickNumberProperties<T> = { [P in keyof T]: T[P] extends number ? T[P] : never; };

在这个例子中,PickNumberProperties 类型会只保留那些值类型是 number 的属性,其他属性则会变为 never,即排除掉。

type PickedPerson = PickNumberProperties<Person>; // PickedPerson 的类型是 { age: number; isActive: never }

如下图所示:

总结

映射类型是 TypeScript 中的一种强大工具,允许我们通过遍历现有类型的属性并修改或生成新类型。它通过 inkeyof 关键字,可以动态地对对象类型的每个属性进行转换,支持修改属性的类型、添加修饰符(如 readonlyoptional)等操作。映射类型还支持与条件类型结合使用,从而实现更复杂的转换逻辑。此外,TypeScript 提供了内置的映射类型工具,如 PartialReadonlyRequiredRecord,帮助开发者高效处理对象类型。

最后更新于:
Copyright © 2025Moment版权所有粤ICP备2025376666