TypeScript映射类型 #

一、映射类型基础 #

1.1 什么是映射类型 #

映射类型建立在索引签名的语法之上,用于创建新类型,新类型基于旧类型的每个属性。

typescript
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

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

type ReadonlyUser = Readonly<User>;

1.2 基本语法 #

typescript
type Mapped<T> = {
    [P in keyof T]: T[P];
};

1.3 keyof操作符 #

keyof获取类型的所有键的联合类型:

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

type UserKeys = keyof User;

二、内置映射类型 #

2.1 Partial #

将所有属性变为可选:

typescript
type Partial<T> = {
    [P in keyof T]?: T[P];
};

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

type PartialUser = Partial<User>;

const user: PartialUser = {
    name: 'Alice'
};

2.2 Required #

将所有属性变为必需:

typescript
type Required<T> = {
    [P in keyof T]-?: T[P];
};

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

type RequiredUser = Required<User>;

const user: RequiredUser = {
    name: 'Alice',
    age: 25
};

2.3 Readonly #

将所有属性变为只读:

typescript
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

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

type ReadonlyUser = Readonly<User>;

const user: ReadonlyUser = {
    name: 'Alice',
    age: 25
};

user.name = 'Bob';

2.4 Pick #

选择部分属性:

typescript
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

interface User {
    id: number;
    name: string;
    email: string;
}

type UserPreview = Pick<User, 'id' | 'name'>;

const preview: UserPreview = {
    id: 1,
    name: 'Alice'
};

2.5 Omit #

排除部分属性:

typescript
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

interface User {
    id: number;
    name: string;
    password: string;
}

type PublicUser = Omit<User, 'password'>;

const user: PublicUser = {
    id: 1,
    name: 'Alice'
};

2.6 Record #

创建对象类型:

typescript
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

type UserMap = Record<string, number>;

const map: UserMap = {
    'a': 1,
    'b': 2
};

三、修饰符 #

3.1 添加修饰符 #

typescript
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

type Optional<T> = {
    [P in keyof T]?: T[P];
};

3.2 移除修饰符 #

使用-移除修饰符:

typescript
type Required<T> = {
    [P in keyof T]-?: T[P];
};

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

3.3 组合使用 #

typescript
type MutableRequired<T> = {
    -readonly [P in keyof T]-?: T[P];
};

四、键重映射 #

4.1 as子句 #

TypeScript 4.1引入了as子句用于键重映射:

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

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

type PersonGetters = Getters<Person>;

4.2 过滤属性 #

typescript
type OnlyStrings<T> = {
    [K in keyof T as T[K] extends string ? K : never]: T[K];
};

interface Mixed {
    name: string;
    age: number;
    email: string;
    active: boolean;
}

type StringProps = OnlyStrings<Mixed>;

4.3 移除前缀 #

typescript
type RemovePrefix<T, P extends string> = {
    [K in keyof T as K extends `${P}${infer Rest}` ? Rest : K]: T[K];
};

interface ApiData {
    apiName: string;
    apiAge: number;
}

type CleanData = RemovePrefix<ApiData, 'api'>;

五、模板字面量类型 #

5.1 基本用法 #

typescript
type EventName = `on${Capitalize<string>}`;

type ClickEvent = 'onClick';
type FocusEvent = 'onFocus';

5.2 结合映射类型 #

typescript
type EventHandlers<T> = {
    [K in keyof T as `on${Capitalize<string & K>}`]: (event: T[K]) => void;
};

interface Events {
    click: MouseEvent;
    focus: FocusEvent;
}

type Handlers = EventHandlers<Events>;

5.3 内置工具类型 #

typescript
type Greeting = 'hello world';

type Upper = Uppercase<Greeting>;
type Lower = Lowercase<Greeting>;
type Capital = Capitalize<Greeting>;
type Uncapital = Uncapitalize<Greeting>;

六、高级应用 #

6.1 深层映射 #

typescript
type DeepPartial<T> = {
    [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

type DeepReadonly<T> = {
    readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

6.2 条件映射 #

typescript
type Nullable<T> = {
    [P in keyof T]: T[P] | null;
};

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

type NullableUser = Nullable<User>;

const user: NullableUser = {
    name: 'Alice',
    age: null
};

6.3 值类型映射 #

typescript
type Stringify<T> = {
    [P in keyof T]: string;
};

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

type StringifiedUser = Stringify<User>;

const user: StringifiedUser = {
    name: 'Alice',
    age: '25',
    active: 'true'
};

6.4 类型转换 #

typescript
type Functionize<T> = {
    [P in keyof T]: () => T[P];
};

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

type LazyUser = Functionize<User>;

const lazyUser: LazyUser = {
    name: () => 'Alice',
    age: () => 25
};

七、实用示例 #

7.1 类型安全的get/set #

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

type Setters<T> = {
    [K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};

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

type UserGetters = Getters<User>;
type UserSetters = Setters<User>;

7.2 代理类型 #

typescript
type Proxy<T> = {
    [K in keyof T]: {
        get(): T[K];
        set(value: T[K]): void;
    };
};

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

type UserProxy = Proxy<User>;

7.3 验证类型 #

typescript
type Validators<T> = {
    [K in keyof T as `${string & K}Validator`]: (value: T[K]) => boolean;
};

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

type UserValidators = Validators<User>;

八、总结 #

本章介绍了TypeScript映射类型:

映射类型基础 #

  1. keyof操作符
  2. 索引签名语法
  3. 属性映射

内置映射类型 #

  1. Partial
  2. Required
  3. Readonly
  4. Pick
  5. Omit
  6. Record

高级特性 #

  1. 修饰符操作
  2. 键重映射
  3. 模板字面量类型
最后更新:2026-03-26