TypeScript 映射类型

映射类型通过 in keyof 遍历一个类型的全部键,对每个键套用统一规则,批量生成新类型的属性,相当于「把类型当作数据来加工」,比逐个手写新接口高效得多,是大量工具类型背后的统一套路。

基本语法

[K in keyof T] 遍历 T 的所有键,配合索引访问 T[K] 读取原属性类型:

interface User {
  name: string;
  age: number;
}

type Flags<T> = { [K in keyof T]: boolean };
type UserFlags = Flags<User>;
// type UserFlags = { name: boolean; age: boolean }

const f: UserFlags = { name: true, age: false };
console.log(f); // 输出:{ name: true, age: false }

keyof T 提供键集合,T[K] 取出对应值类型,二者组合即可变换任意结构。

修饰符的增删

映射时可追加 readonly?,用 - 前缀移除修饰:

interface Todo {
  title: string;
  done: boolean;
}

type Mutable<T> = { -readonly [K in keyof T]: T[K] };       // 去掉只读
type Optional<T> = { [K in keyof T]?: T[K] };               // 全部变可选
type ReadonlyAll<T> = { readonly [K in keyof T]: T[K] };    // 全部只读

interface Fixed {
  readonly id: number;
  name: string;
}
const m: Mutable<Fixed> = { id: 1, name: "x" };
m.id = 2; // 合法:readonly 已被移除

+readonly+? 表示添加(默认就是添加),-readonly-? 表示移除。

内置工具类型的原型实现

Partial、Readonly、Required、Pick 都可以用映射类型一行写出:

type MyPartial<T> = { [K in keyof T]?: T[K] };
type MyReadonly<T> = { readonly [K in keyof T]: T[K] };
type MyRequired<T> = { [K in keyof T]-?: T[K] };
type MyPick<T, Keys extends keyof T> = { [K in Keys]: T[K] };

interface User {
  name: string;
  age: number;
}
const p: MyPartial<User> = { name: "张三" }; // 只给部分字段
const r: MyRequired<MyPartial<User>> = { name: "张三", age: 30 };

理解了映射语法,官方工具类型的源码就一目了然。

键重映射 as

TS 4.1 起可在键后加 as 新键,按规则改名或过滤键,甚至拼出模板字符串键名:

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

interface Point {
  x: number;
  y: number;
}
// type Getters<Point> = { getX: () => number; getY: () => number }
const g: Getters<Point> = { getX: () => 1, getY: () => 2 };

// as 分支产出 never 即删除该键
type NoDone<T> = { [K in keyof T as K extends "done" ? never : K]: T[K] };
type N = NoDone<{ a: number; done: boolean }>; // type N = { a: number }

键重映射让映射类型从「改类型」升级到「改结构、改键名」,能力大增。

小结:映射类型 = [K in keyof T] 遍历 + 修饰符增删 + T[K] 取原值,配合 as 还能重命名键;Partial、Pick 等大批工具类型都建立在它之上,掌握它等于掌握类型变换的核心。

笔记加载中…