映射类型( Mapped types )允许我们从现有类型中创建新的类型。例如结合索引类型,将一个类型的所有属性设置为 boolean

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
type BooleanFlags<Type> = {
  [Property in keyof Type]: boolean;
};

type FeatureFlags = {
  darkMode: () => void;
  newUserProfile: () => void;
};
 
type FeatureOptions = BooleanFlags<FeatureFlags>;
// type FeatureOptions = {
//    darkMode: boolean;
//    newUserProfile: boolean;
// }

或者另一个常见的使用场景:将一个对象的所有属性变为只读 (read-only)

1
2
3
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

Readonly 类型的作用是将传入的属性变为只读。例如 TypeScript 中是这样定义 Object.freeze的:

1
2
3
4
5
6
7
8
interface ObjectConstructor {
  /**
   * 防止修改现有的属性和值
   * 也防止新增属性
   * @param o 需要被锁的对象
   */
  freeze<T>(o: T): Readonly<T>;
}

如我们所见,Object.freeze 函数返回使用 Readonly 修饰符映射的对象。

还有另一个修饰符 ?,用于设置属性可选:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 删除属性中的可选属性
type Optional<Type> = {
  [Property in keyof Type]?: Type[Property];
};
 
type User = {
  id: string;
  name: string;
  age: number;
};
 
type MaybeUser = Optional<User>;

// type MaybeUser = {
//   id?: string;
//   name?: string;
//   age?: number;
// };

也可以通过前缀 - 或者 + 删除或者添加这些修饰符,如果没有写前缀,相当于使用了 + 前缀。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 删除属性中的只读属性
type CreateMutable<Type> = {
  -readonly [Property in keyof Type]: Type[Property];
};
 
type LockedAccount = {
  readonly id: string;
  readonly name: string;
};
 
type UnlockedAccount = CreateMutable<LockedAccount>;

// type UnlockedAccount = {
//    id: string;
//    name: string;
// }

// 删除属性中的可选属性
type Concrete<Type> = {
  [Property in keyof Type]-?: Type[Property];
};
 
type MaybeUser = {
  id: string;
  name?: string;
  age?: number;
};
 
type User = Concrete<MaybeUser>;
// type User = {
//    id: string;
//    name: string;
//    age: number;
// }