# 定义
Typescript
提供了几种 实用工具类型, 方便进行常见的类型转换。这些实用工具类型在全局范围内都可以使用。
# 实用工具类型
变量 K
, T
, V
详见常见的一些泛型变量含义
# Partial<T>
Typescript 2.1 新增工具方法 (opens new window)
# 定义
构造一个类型 T
, 将类型 T
的所有属性设置为 可选属性。该工具类方法将返回一个表示输入类型 (T)
的所有自己的类型。
# 使用
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',
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 源码实现
type Partial<T> = {
[P in keyof T]?: T[P];
}
2
3
4
# Readonly<T>
Typescript 2.1 新增工具方法 (opens new window)
# 定义
构造一个所有属性都设置为 只读 属性的类型 T
, 这意味着 无法 再次对所有构造类型的属性进行 赋值。
# 使用
interface Properties {
cute: boolean;
handsome: boolean;
}
let mine: Readonly<Properties> = {
cute: true,
handsome: true,
}
mine.handsome = false;
// Cannot assign to 'handsome' because it is a read-only property.(2540)
2
3
4
5
6
7
8
9
10
11
12
13
该工具对于表示在运行时会失败的赋值表达式很有用, 例如 Object freeze
(opens new window)
function freeze<T>(obj: T): Readonly<T>;
2
# 源码实现
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
2
3
# Record<K, T>
Typescript 2.1 新增工具方法 (opens new window)
# 定义
构造一个属性为 K
类型, 属性值为 T
类型的类型。可用于将一个类型的属性 映射到 另一个类型中。
# 使用
// Record
interface Page {
title?: string | undefined;
content?: string | undefined;
}
type PageType = 'home' | 'about' | 'contact';
const site: Record<PageType, Page> = {
home: {
content: 'home'
},
about: {
title: 'about',
content: 'about'
},
contact: {
title: 'contact',
// Error: Type '{ title: string; name: string; }' is not assignable to type 'Page'.
// Object literal may only specify known properties,
// and 'name' does not exist in type 'Page'.
name: 'Rain120'
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 源码实现
type Record<K extends keyof any, T> = {
[P in K]: T;
}
2
3
# Pick<T, K>
Typescript 2.1 新增工具方法 (opens new window)
# 定义
通过从类型 T
选取 属性 K
的集合来构造类型。
# 使用
interface Todo {
title: string;
description: string;
isCompleted: boolean;
}
type TodoWithDay = Pick<Todo, 'title' | 'isCompleted'>
const plan: TodoWithDay = {
title: 'Writing for Typescript Guide',
isCompleted: true
}
2
3
4
5
6
7
8
9
10
11
12
13
# 源码实现
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
}
2
3
# Omit<T, K>
Typescript 3.5 新增工具方法 (opens new window)
# 定义
通过从 类型 T
中 选取 所有属性, 然后 删除 传入的属性 K
来构造新类型。
# 使用
interface Todo {
title: string;
description: string;
isCompleted: boolean;
}
type TodoWithDay = Omit<Todo, 'description'>
const plan: TodoWithDay = {
title: 'Writing for Typescript Guide',
isCompleted: true
}
2
3
4
5
6
7
8
9
10
11
12
# 源码实现
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
# Exclude<T, U>
Typescript 2.8 新增工具方法 (opens new window)
# 定义
通过从类型 T
中 剔除 可赋值给 U
的属性来构造一个新类型。
# 使用
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
2
3
4
5
6
# 源码实现
type Exclude<T, U> = T extends U ? never : T;
# Extract<T, U>
Typescript 2.8 新增工具方法 (opens new window)
# 定义
通过从类型 T
中 挑选 可赋值给 U
的属性来构造一个新类型。
# 使用
type T0 = Extract<'a' | 'b', 'a'> // 'a'
type T1 = Extract<'a' | 'b' | (() => void), Function> // () => void
2
3
# 源码实现
type Extract<T, U> = T extends U ? T : never;
# NonNullable<T>
Typescript 2.8 新增工具方法 (opens new window)
# 定义
# 使用
// NonNullable
type T0 = NonNullable<'a' | null> // 'a'
type T1 = NonNullable<'a' | null | undefined> // 'a'
2
3
4
5
# 源码实现
type NonNullable<T> = T extends null | undefined ? never : T;
# Parameters<T>
# 定义
构造一个关于函数类型 T
的 参数类型 的元组类型。请到 #26019 (opens new window)
# 使用
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>; // never
type T7 = Parameters<string>; // Error
type T8 = Parameters<Function>; // Error
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 源码实现
type Parameters<T> = {
T extends (...args: infer P) => any ? P : never
}
2
3
# ConstructorParameters<T>
# 定义
通过 ConstructorParameters
类型, 我们可以 提取 构造函数类型的 所有参数类型。 它会生成构造函数所具有的所有参数类型的元组类型(如果 T
不是函数, 则不返回)。
# 使用
type T0 = ConstructorParameters<ErrorConstructor>; // [(string | undefined)?]
type T1 = ConstructorParameters<FunctionConstructor>; // string[]
type T2 = ConstructorParameters<RegExpConstructor>; // [string, (string | undefined)?]
2
3
4
5
# 源码实现
type ConstructorParameters<T> = {
T extends new (...args: infer P) => any ? P : never
}
2
3
# ReturnType<T>
Typescript 2.8 新增工具方法 (opens new window)
# 定义
构造一个由函数 T
的返回类型组成的新类型。
# 使用
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 源码实现
type ReturnType<
T extends (...args: any[]) => any
> = T extends (...ages: any[]) => infer R ? R : any;
2
3
# InstanceType<T>
Typescript 2.8 新增工具方法 (opens new window)
# 定义
构造y一个由构造函数 T
的 实例类型 组成的新类型。
# 使用
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 源码实现
type InstanceType<
T extends new (...args: any[]) => any
> = T extends new (...args: any[]) => infer R : R : any;
2
3
# Required<T>
Typescript 2.8 rc 新增工具方法 (opens new window)
# 定义
# 使用
interface Profile {
name: string;
age?: number;
gender?: string;
};
// OK
const profile: Profile = {
name: 'Rain120',
};
// Type '{ name: string; }' is missing the following properties
// from type 'Required<Profile>': age, gender(2739)
const ID_Card: Required<Profile> = {
name: 'Rain120',
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 源码实现
type Required<T> = {
[P in keyof T]-?: T[P];
}
2
3
操作符相关问题请到 Here
# ThisParameterType
# 定义
提取函数类型的 this
参数的类型, 如果函数类型没有 this
参数, 则 未知 (opens new window)。
注意: 仅当启用 --strictFunctionTypes
时, 此类型才能正常工作。 请到 #32964 (opens new window)
# 使用
function toHex(this: Number) {
return this.toString(16);
}
function numberToString(n: ThisParameterType<typeof toHex>) {
return toHex.apply(n);
}
2
3
4
5
6
7
# OmitThisParameter
# 定义
从函数类型中删除 this
参数。
注意: 仅当启用 --strictFunctionTypes
时, 此类型才能正常工作。请到 #32964 (opens new window)
# 使用
function toHex(this: Number) {
return this.toString(16);
}
// The return type of `bind` is already using `OmitThisParameter`, this is just for demonstration.
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);
console.log(fiveToHex());
2
3
4
5
6
7
8
# ThisType<T>
# 定义
该工具 不会返回转换后 的类型。 相反, 它是一个用作上下文类型中键入 this
类型的标记。 注意, 必须启用 –noImplicitThis
标志才能使用此工具。
# 使用
// 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);
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
- 在上面的示例中,
makeObject
的参数中的methods
对象具有包含ThisType
的上下文类型; 因此, 在methods
对象内的方法中, 方法的this
类型为{x: number, y: number}&{moveBy (dx: number, dy: number) : number}
。 请注意methods
属性的类型是如何同时成为方法中this
类型的推断目标和来源的。 ThisType
标记接口仅仅是在lib.d.ts
中声明的一个空接口。 除了在对象字面量的上下文类型中被识别外, 该接口的作用类似于任何空接口。
# 快来耍耍啊
# 🌰🌰
// template
# 游乐场
# 参考答案
// answer
# 参考资料
handbook - utility-types (opens new window)
handbook - mapped-types (opens new window)
Microsoft TypeScript wiki Road map (opens new window)
Microsoft TypeScript #21316 Conditional Types (opens new window)
Microsoft TypeScript #21496 infer pull request (opens new window)