13. 常用类型工具
约 1982 字大约 7 分钟
2025-06-02
TypeScript 提供了一些内置的类型工具,用来方便地处理各种类型,以及生成新的类型。
这些类型工具都是语言本身提供的,可以直接使用。
1、Exclude<UnionType, ExcludedMembers>
Exclude<UnionType, ExcludedMembers>
用来从联合类型 UnionType
里面,删除某些类型 ExcludedMembers
,组成一个新的类型返回。
type T1 = Exclude<"a" | "b" | "c", "a">; // 'b'|'c'
type T2 = Exclude<"a" | "b" | "c", "a" | "b">; // 'c'
type T3 = Exclude<string | (() => void), Function>; // string
type T4 = Exclude<string | string[], any[]>; // string
type T5 = Exclude<(() => void) | null, Function>; // null
type T6 = Exclude<200 | 400, 200 | 201>; // 400
type T7 = Exclude<number, boolean>; // number
Exclude<UnionType, ExcludedMembers>
的实现如下。
type Exclude<T, U> = T extends U ? never : T;
上面代码中,等号右边的部分,表示先判断 T
是否兼容 U
,如果是的就返回 never
类型,否则返回当前类型 T
。由于 never
类型是任何其他类型的子类型,它跟其他类型组成联合类型时,可以直接将 never
类型从联合类型中“消掉”,因此 Exclude<T, U>
就相当于删除兼容的类型,剩下不兼容的类型。
2、Extract<Type, Union>
Extract<UnionType, Union>
用来从联合类型 UnionType
之中,提取指定类型 Union
,组成一个新类型返回。它与 Exclude<T, U>
正好相反。
type T1 = Extract<"a" | "b" | "c", "a">; // 'a'
type T2 = Extract<"a" | "b" | "c", "a" | "b">; // 'a'|'b'
type T3 = Extract<"a" | "b" | "c", "a" | "d">; // 'a'
type T4 = Extract<string | string[], any[]>; // string[]
type T5 = Extract<(() => void) | null, Function>; // () => void
type T6 = Extract<200 | 400, 200 | 201>; // 200
如果参数类型 Union
不包含在联合类型 UnionType
之中,则返回 never
类型。
type T = Extract<string | number, boolean>; // never
Extract<UnionType, Union>
的实现如下。
type Extract<T, U> = T extends U ? T : never;
3、NonNullable<Type>
NonNullable<Type>
用来从联合类型 Type
删除 null
类型和 undefined
类型,组成一个新类型返回,也就是返回 Type
的非空类型版本。
// string|number
type T1 = NonNullable<string | number | undefined>;
// string[]
type T2 = NonNullable<string[] | null | undefined>;
type T3 = NonNullable<boolean>; // boolean
type T4 = NonNullable<number | null>; // number
type T5 = NonNullable<string | undefined>; // string
type T6 = NonNullable<null | undefined>; // never
NonNullable<Type>
的实现如下。
type NonNullable<T> = T & {};
上面代码中,T & {}
等同于求 T & Object
的交叉类型。由于 TypeScript 的非空值都属于 Object
的子类型,所以会返回自身;而 null
和 undefined
不属于 Object
,会返回 never
类型。
4、Omit<Type, Keys>
Omit<Type, Keys>
用来从对象类型 Type
中,删除指定的属性 Keys
,组成一个新的对象类型返回。
interface A {
x: number;
y: number;
}
type T1 = Omit<A, "x">; // { y: number }
type T2 = Omit<A, "y">; // { x: number }
type T3 = Omit<A, "x" | "y">; // { }
上面示例中,Omit<Type, Keys>
从对象类型 A
里面删除指定属性,返回剩下的属性。
指定删除的键名 Keys
可以是对象类型 Type
中不存在的属性,但必须兼容 string|number|symbol
。
interface A {
x: number;
y: number;
}
type T = Omit<A, "z">; // { x: number; y: number }
上面示例中,对象类型 A
中不存在属性 z
,所以就原样返回了。
Omit<Type, Keys>
的实现如下。
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
5、Partial<Type>
Partial<Type>
返回一个新类型,将参数类型 Type
的所有属性变为可选属性。
interface A {
x: number;
y: number;
}
type T = Partial<A>; // { x?: number; y?: number; }
Partial<Type>
的实现如下。
type Partial<T> = {
[P in keyof T]?: T[P];
};
6、Pick<Type, Keys>
Pick<Type, Keys>
返回一个新的对象类型,第一个参数 Type
是一个对象类型,第二个参数 Keys
是 Type
里面被选定的键名。
interface A {
x: number;
y: number;
}
type T1 = Pick<A, "x">; // { x: number }
type T2 = Pick<A, "y">; // { y: number }
type T3 = Pick<A, "x" | "y">; // { x: number; y: number }
上面示例中,Pick<Type, Keys>
会从对象类型 A
里面挑出指定的键名,组成一个新的对象类型。
指定的键名 Keys
必须是对象键名 Type
里面已经存在的键名,否则会报错。
interface A {
x: number;
y: number;
}
type T = Pick<A, "z">; // 报错
上面示例中,对象类型A
不存在键名 z
,所以报错了。
Pick<Type, Keys>
的实现如下。
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
7、Readonly<Type>
Readonly<Type>
返回一个新类型,将参数类型 Type
的所有属性变为只读属性。
interface A {
x: number;
y?: number;
}
// { readonly x: number; readonly y?: number; }
type T = Readonly<A>;
上面示例中,y
是可选属性,Readonly<Type>
不会改变这一点,只会让 y
变成只读。
Readonly<Type>
的实现如下。
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
我们可以自定义类型工具 Mutable<Type>
,将参数类型的所有属性变成可变属性。
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
上面代码中,-readonly
表示去除属性的只读标志。
相应地,+readonly
就表示增加只读标志,等同于 readonly
。因此,Readonly<Type>
的实现也可以写成下面这样。
type Readonly<T> = {
+readonly [P in keyof T]: T[P];
};
Readonly<Type>
可以与 Partial<Type>
结合使用,将所有属性变成只读的可选属性。
interface Person {
name: string;
age: number;
}
const worker: Readonly<Partial<Person>> = { name: "张三" };
worker.name = "李四"; // 报错
8、Record<Keys, Type>
Record<Keys, Type>
返回一个对象类型,参数 Keys
用作键名,参数 Type
用作键值类型。
// { a: number }
type T = Record<"a", number>;
上面示例中,Record<Keys, Type>
的第一个参数 a
,用作对象的键名,第二个参数 number
是 a
的键值类型。
参数 Keys
可以是联合类型,这时会依次展开为多个键。
// { a: number, b: number }
type T = Record<"a" | "b", number>;
上面示例中,第一个参数是联合类型 'a'|'b'
,展开成两个键名 a
和 b
。
如果参数 Type
是联合类型,就表明键值是联合类型。
// { a: number|string }
type T = Record<"a", number | string>;
参数 Keys
的类型必须兼容 string|number|symbol
,否则不能用作键名,会报错。
Record<Keys, Type>
的实现如下。
type Record<K extends string | number | symbol, T> = { [P in K]: T };
9、Required<Type>
Required<Type>
返回一个新类型,将参数类型 Type
的所有属性变为必选属性。它与 Partial<Type>
的作用正好相反。
interface A {
x?: number;
y: number;
}
type T = Required<A>; // { x: number; y: number; }
Required<Type>
的实现如下。
type Required<T> = {
[P in keyof T]-?: T[P];
};
上面代码中,符号 -?
表示去除可选属性的“问号”,使其变成必选属性。
相对应地,符号 +?
表示增加可选属性的“问号”,等同于 ?
。因此,前面的 Partial<Type>
的定义也可以写成下面这样。
type Partial<T> = {
[P in keyof T]+?: T[P];
};
10、ReadonlyArray<Type>
ReadonlyArray<Type>
用来生成一个只读数组类型,类型参数 Type
表示数组成员的类型。
const values: ReadonlyArray<string> = ["a", "b", "c"];
values[0] = "x"; // 报错
values.push("x"); // 报错
values.pop(); // 报错
values.splice(1, 1); // 报错
上面示例中,变量 values
的类型是一个只读数组,所以修改成员会报错,并且那些会修改源数组的方法 push()
、pop()
、splice()
等都不存在。
ReadonlyArray<Type>
的实现如下。
interface ReadonlyArray<T> {
readonly length: number;
readonly [n: number]: T;
// ...
}
11、ReturnType<Type>
ReturnType<Type>
提取函数类型 Type
的返回值类型,作为一个新类型返回。
type T1 = ReturnType<() => string>; // string
type T2 = ReturnType<
() => {
a: string;
b: number;
}
>; // { a: string; b: number }
type T3 = ReturnType<(s: string) => void>; // void
type T4 = ReturnType<() => () => any[]>; // () => any[]
type T5 = ReturnType<typeof Math.random>; // number
type T6 = ReturnType<typeof Array.isArray>; // boolean
如果参数类型是泛型函数,返回值取决于泛型类型。如果泛型不带有限制条件,就会返回 unknown
。
type T1 = ReturnType<<T>() => T>; // unknown
type T2 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
如果类型不是函数,会报错。
type T1 = ReturnType<boolean>; // 报错
type T2 = ReturnType<Function>; // 报错
any
和 never
是两个特殊值,分别返回 any
和 never
。
type T1 = ReturnType<any>; // any
type T2 = ReturnType<never>; // never
ReturnType<Type>
的实现如下。
type ReturnType<T extends (...args: any) => any> = T extends (
...args: any
) => infer R
? R
: any;
更新日志
e7112
-1于