← 返回题目列表

TypeScript 映射类型是什么?如何实现 Partial 和 Readonly?

高频 中等 第 17 / 32 题 更新于 2026/07/29
TypeScript映射类型工具类型

简化版

映射类型可以遍历一个类型的 key,并按规则生成新类型。Partial<T> 是把所有属性变成可选,Readonly<T> 是把所有属性变成只读,它们都基于 [K in keyof T] 实现。

详细版

核心写法:

type MyPartial<T> = {
  [K in keyof T]?: T[K];
};

type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};

映射类型常用于批量转换属性修饰符和值类型。 面试重点是理解 keyof T 拿 key,K in ... 遍历 key,T[K] 取属性值类型。

完整版教学

一、映射类型解决重复改属性的问题

如果一个对象类型有 20 个字段,想把它们都变成可选,手写会很痛苦。 映射类型提供了类型层面的“遍历 key”能力。 它让我们可以基于旧类型批量生成新类型。

type User = {
  id: number;
  name: string;
  active: boolean;
};

目标是得到:

id?: number
name?: string
active?: boolean

不用重复写 3 个字段,映射类型可以统一转换。

二、keyofin、索引访问是三件套

映射类型的核心三件套是 keyof TK inT[K]keyof T 得到属性名联合。 K in keyof T 遍历这些属性名。 T[K] 拿到每个属性对应的值类型。

type Copy<T> = {
  [K in keyof T]: T[K];
};

User 来说:

keyof User = 'id' | 'name' | 'active'
K 依次取每个 key
T[K] 取 number / string / boolean

这就是很多工具类型的基础。

三、Partial 的实现

Partial<T> 把所有属性改成可选。 它只是在映射属性名后加了 ? 修饰符。 值类型保持不变。

type MyPartial<T> = {
  [K in keyof T]?: T[K];
};

type PartialUser = MyPartial<User>;
原字段转换后
id: numberid?: number
name: stringname?: string
active: booleanactive?: boolean

表单编辑、PATCH 请求、配置覆盖都经常用 Partial。 但它是浅层的,嵌套对象不会自动深度可选。

四、Readonly 的实现

Readonly<T> 把所有属性加上 readonly。 这表示属性不能通过该类型引用被重新赋值。 它同样是浅层的。

type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};

const user: MyReadonly<User> = {
  id: 1,
  name: 'Alice',
  active: true,
};

// user.name = 'Bob'; // 报错

readonly 是类型层约束,不等于运行时冻结。 如果运行时代码绕过类型系统,仍可能修改对象。

五、修饰符可以添加也可以移除

映射类型支持 +?-?+readonly-readonly+ 通常可省略。 - 表示移除修饰符。

type RequiredAgain<T> = {
  [K in keyof T]-?: T[K];
};

type Mutable<T> = {
  -readonly [K in keyof T]: T[K];
};

流程如下:

遍历 key
  -> 决定是否加 readonly
  -> 决定是否加 ?
  -> 决定值类型 T[K]

这让工具类型可以表达非常丰富的批量转换。

六、键重映射让映射类型更强

较新的 TypeScript 支持在映射类型中用 as 重映射 key。 例如把所有字段名前加 get,生成 getter 类型。 这类题在中高级面试中很常见。

type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

记忆钩子:映射类型就是类型世界里的 for…in,keyof 给范围,T[K] 取值,修饰符决定怎么改。

这也是很多高级工具类型的基础能力。

七、常见误区与追问

  • 误区:映射类型会生成运行时代码。 它只存在于类型系统,编译后会被擦除。
  • 误区:Partial 会深度可选。 内置 Partial 是浅层转换,嵌套对象需要自定义 DeepPartial。
  • 误区:Readonly 等于 Object.freeze。 Readonly 是编译期约束,不是运行时冻结。
  • 追问:T[K] 是什么? 它是索引访问类型,用 key 取对象类型上对应属性的值类型。
  • 追问:如何移除 readonly? 在映射类型里使用 -readonly 修饰符。
  • 追问:如何改 key 名? 使用键重映射语法 [K in keyof T as NewKey]

八、加强记忆

映射类型按公式记:[K in keyof T]: T[K]。要变可选就加 ?,要只读就加 readonly,要改名就用 as。面试时手写 PartialReadonly,再补浅层限制和修饰符移除,基本就能覆盖核心考点。