实用类型

状态: 初稿

介绍

TypeScript 为你提供许多用于常用类型转换的实用类型. 这些工具全局可用.

Partial<T>

构建一个新类型, 把所有类型为 T 的属性设为”可选”. 该工具返回一个代表给定类型所有子类型的类型.

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface Todo {
title: string;
description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}

const todo1 = {
title: 'organize desk',
description: 'clear clutter',
};

const todo2 = updateTodo(todo1, {
description: 'throw out trash',
});

Readonly<T>

构建一个类型, 把所有类型为 T 的属性设为 readonly, 表示结果类型的属性不可重赋值.

实例
1
2
3
4
5
6
7
8
9
interface Todo {
title: string;
}

const todo: Readonly<Todo> = {
title: 'Delete inactive users',
};

todo.title = 'Hello'; // Error: cannot reassign a readonly property

这个工具可以代表在运行期会失败的赋值表达式 (即: 当试图对一个 frozen object 的属性重赋值).

Object.freeze
1
function freeze<T>(obj: T): Readonly<T>;

Record<K,T>

构建一个类型, 它有一个类型为 T 的属性组 K. 这个工具可以把一类型的属性映射为另一类型.

实例
1
2
3
4
5
6
7
8
9
10
11
interface PageInfo {
title: string;
}

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

const x: Record<Page, PageInfo> = {
about: { title: 'about' },
contact: { title: 'contact' },
home: { title: 'home' },
};

Pick<T,K>

T 中挑选属性组 K, 构建一个类型.

实例
1
2
3
4
5
6
7
8
9
10
11
12
interface Todo {
title: string;
description: string;
completed: boolean;
}

type TodoPreview = Pick<Todo, 'title' | 'completed'>;

const todo: TodoPreview = {
title: 'Clean room',
completed: false,
};

Omit<T,K>

挑选 T 中所有属性, 然后移除属性组 K, 构建一个类型.

实例
1
2
3
4
5
6
7
8
9
10
11
12
interface Todo {
title: string;
description: string;
completed: boolean;
}

type TodoPreview = Omit<Todo, 'description'>;

const todo: TodoPreview = {
title: 'Clean room',
completed: false,
};

Exclude<T,U>

T 排除所有能赋值给 U 的属性, 构建一个类型.

实例
1
2
3
type T0 = Exclude<"a" | "b" | "c", "a">;  // "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
type T2 = Exclude<string | number | (() => void), Function>; // string | number

Extract<T,U>

T 中提取所有能赋值给 U 的属性, 构建一个类型.

实例
1
2
type T0 = Extract<"a" | "b" | "c", "a" | "f">;  // "a"
type T1 = Extract<string | number | (() => void), Function>; // () => void

NonNullable<T>

T 中排除所有 nullundefined, 构建一个类型.

实例
1
2
type T0 = NonNullable<string | number | undefined>;  // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]

Parameters<T>

从函数类型 T 的参数类型构建一个元组类型.

实例
1
2
3
4
5
6
7
8
9
declare function f1(arg: { a: number, b: string }): void
type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<(<T>(arg: T) => T)>; // [unknown]
type T4 = Parameters<typeof f1>; // { a: number, b: string }
type T5 = Parameters<any>; // unknown[]
type T6 = Parameters<never>; // any
type T7 = Parameters<string>; // Error
type T8 = Parameters<Function>; // Error

ReturnType<T>

构建一个类型, 它由函数 T 的返回值类型组成.

实例
1
2
3
4
5
6
7
8
9
10
declare function f1(): { a: number, b: string }
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<(<T>() => T)>; // {}
type T3 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
type T4 = ReturnType<typeof f1>; // { a: number, b: string }
type T5 = ReturnType<any>; // any
type T6 = ReturnType<never>; // any
type T7 = ReturnType<string>; // Error
type T8 = ReturnType<Function>; // Error

InstanceType<T>

构建一个类型, 它由构造器函数类型 T 的实例类型组成.

实例
1
2
3
4
5
6
7
8
9
10
class C {
x = 0;
y = 0;
}

type T0 = InstanceType<typeof C>; // C
type T1 = InstanceType<any>; // any
type T2 = InstanceType<never>; // any
type T3 = InstanceType<string>; // Error
type T4 = InstanceType<Function>; // Error

Required<T>

构建一个类型, 把 T 中所有属性设为 “必选”.

实例
1
2
3
4
5
6
7
8
interface Props {
a?: number;
b?: string;
};

const obj: Props = { a: 5 }; // OK

const obj2: Required<Props> = { a: 5 }; // Error: property 'b' missing

ThisType<T>

这个工具不返回一个经转换的类型. 相反, 它作为上下文 this 类型的标识. 注意, 要使用这个工具, 必须打开 --noImplicitThis 选项.

实例
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
// Compile with --noImplicitThis

type ObjectDescriptor<D, M> = {
data?: D;
methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M
}

function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
let data: object = desc.data || {};
let methods: object = desc.methods || {};
return { ...data, ...methods } as D & M;
}

let obj = makeObject({
data: { x: 0, y: 0 },
methods: {
moveBy(dx: number, dy: number) {
this.x += dx; // Strongly typed this
this.y += dy; // Strongly typed this
}
}
});

obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);

上例中, makeObject 的参数中的 methods 对象有一个包括 ThisType<D & M> 的上下文类型, 因此 methods 对象内方法中的 this 的类型是 { x: number, y: number } & { moveBy(dx: number, dy: number): number }. 注意 methods 属性的类型是如何同时成为推断方法中 this 类型的目标和源的.

ThisType<T> 标记接口只是一个在 lib.d.ts 声明的空接口. 除了可以在对象字面量的上下文类型中被识别, 它与普通空接口没有区别.

如果这篇文章对您有用,可以考虑打赏:)