Skip to content
On this page

映射类型

通过映射类型,可以从一个旧的类型,生成一个新的类型,比如

只读 readonly

把一个类型 / 接口中的所有属性变为

typescript
interface Obj {
  a: string;
  b: number;
  c: boolean;
}
/*
类型推断为
type ReadonlyObj = {
    readonly a: string;
    readonly b: number;
    readonly c: boolean;
}
*/
type ReadonlyObj = Readonly<Obj>;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Readonly 源码实现原理

typescript
/**
 * Make all properties in T readonly
 */
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};
1
2
3
4
5
6

Readonly 是一个可索引类型的泛型接口, 索引签名是 P in keyof TT 是索引类型的查询操作符,表示类型 T 所有属性的联合类型, P in 相当于执行了一次 for in 操作, 会把变量 P 依次绑定到 T 的属性上, 索引签名的返回值 是一个索引访问操作符 - T[P], 代表属性 P 所指定的类型 最后加上 readonly 就把所有属性变成了只读

可选 Partial

把一个类型 / 接口中的所有属性变为

typescript
interface Obj {
  a: string;
  b: number;
  c: boolean;
}
/*
类型推断为
type PartialObj = {
    a?: string | undefined;
    b?: number | undefined;
    c?: boolean | undefined;
}
*/
type PartialObj = Partial<Obj>;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Partial 源码实现原理

typescript
/**
 * Make all properties in T optional
 */
type Partial<T> = {
  [P in keyof T]?: T[P];
};
1
2
3
4
5
6

必填 Required

typescript
interface Foo {
    name: string
    age?: number
}
type Bar = Required<Foo>
// 相当于
type Bar = {
    name: string
    age: string
}
1
2
3
4
5
6
7
8
9
10

源码

typescript
type Require<T> = {
    [p in keyof T]-?: T[P]
}
1
2
3

抽取 Pick

一个类型 / 接口中的一些子集

typescript
interface Obj {
  a: string;
  b: number;
  c: boolean;
}
/*
类型推断为
type PickObj = {
    a: string;
    b: number;
}
*/
type PickObj = Pick<Obj, "a" | "b">;
1
2
3
4
5
6
7
8
9
10
11
12
13

Pick 源码实现原理

typescript
/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

1
2
3
4
5
6
7

T 代表要抽取的对象

K 有一个约束:一定是来自 T 所有属性字面量的联合类型

新的类型 / 属性一定要从 K 中选取,

以上三种 官方称为 同态, 只会作用于指定的属性(如上面的 Obj),而不会引入新的属性,

Record

Record 的内部定义,接收两个泛型参数;Record 后面的泛型就是对象键和值的类型 一个对象的 key 和 value 类型

Record<string, never> 空对象 Record<string, unknown> 任意对象 {} 任何不为空的对象

typescript
interface PageInfo {
  title: string;
}

type Page = "home" | "about" | "contact";

const nav: Record<Page, PageInfo> = {
  about: { title: "about" },
  contact: { title: "contact" },
  home: { title: "home" },
};
1
2
3
4
5
6
7
8
9
10
11

比如我需要一个对象,有 ABC 三个属性,属性的值必须是数字,那么就这么写:

typescript
type keys = 'A' | 'B' | 'C'
const result: Record<keys, number> = {
  A: 1,
  B: 2,
  C: 3
}
1
2
3
4
5
6

源码

typescript
type Record<K extends string | number | symbol, T> = {
    [P in K]: T;
}
1
2
3

Exclude

作用:如果 T 是 U 的子类型则返回 never 不是则返回 T

typescript
type A = number | string | boolean
type B = number | boolean

type Foo = Exclude<A, B>
// 相当于
type Foo = string
1
2
3
4
5
6

源码

typescript
type Exclude<T, U> = T extends U ? never : T
1

Extract

和 Exclude 相反

typescript
type A = number | string | boolean
type B = number | boolean

type Foo = Extract<A, B>
// 相当于
type Foo = number | boolean
1
2
3
4
5
6

源码

typescript
type Extract<T, U> = T extends U ? T : never
1

Omit

作用:生成一个新类型,该类型拥有 T 中除了 K 属性以外的所有属性

typescript
type Foo = {
	name: string
	age: number
}

type Bar = Omit<Foo, 'age'>
// 相当于
type Bar = {
	name: string
}
1
2
3
4
5
6
7
8
9
10

源码

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

NonNullable

从泛型 T 中排除掉 null 和 undefined

typescript
NonNullable<T>
1

源码

typescript
type NonNullable<T> = T extends null | undefined ? never : T;

type t = NonNullable<'name' | undefined | null>;
/* type t = 'name' */
1
2
3
4

Parameters

从函数类型的参数中使用的类型构造元组类型。

typescript
function foo(p1: string, p2: number) {}

type params = Parameters<typeof foo>; // --> type params = [p1: string, p2: number]
1
2
3

源码

typescript
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

1
2

ConstructorParameters

typescript
class A {
  private name;
  private age;
  constructor(name: string, age: number) {
    this.age = age;
    this.name = name;
  }
}

type B = ConstructorParameters<typeof A>;
1
2
3
4
5
6
7
8
9
10

源码

typescript
type ConstructorParameters<T extends abstract new (...args: any) => any> =
  T extends abstract new (...args: infer P) => any ? P : never;
1
2

限制 string

  • Uppercase 约束 小写
  • Lowercase 约束 大写
  • Capitalize 约束 首字母大写
  • Uncapitalize 约束 首字母小写
typescript
const _uppercase: Uppercase<'hello'> = 'HELLO';
const _lowercase: Lowercase<'hello'> = 'hello';
const _capitalize: Capitalize<'hello'> = 'Hello';
const _uncapitalize: Uncapitalize<'Hello'> = 'hello';
1
2
3
4

总结

映射类型本质上是一个预先定义的泛型接口,通常还会结合索引类型获取对象的属性和属性值,从而将一个对象映射成我们想要的结构。

沪ICP备20006251号-1