TypeScript 提供了一些内置的类型工具,用来方便地处理各种类型,以及生成新的类型。
Awaited<Type>
Awaited<Type>用来取出 Promise 的返回值类型,适合用在描述then()方法和 await 命令的参数类型。
// string
type A = Awaited<Promise<string>>;
可以返回多重 Promise 的返回值类型。
// number
type B = Awaited<Promise<Promise<number>>>;
如果它的类型参数不是 Promise 类型,那么就会原样返回。
Awaited<Type>的实现如下。
type Awaited<T> =
T extends null | undefined ? T :
T extends object & {
then(
onfulfilled: infer F,
...args: infer _
): any;
} ? F extends (
value: infer V,
...args: infer _
) => any ? Awaited<...> : never:
T;
ConstructorParameters<Type>
ConstructorParameters<Type>提取构造方法Type的参数类型,组成一个元组类型返回。
type T1 = ConstructorParameters<
new (x: string, y: number) => object
>; // [x: string, y: number]
type T2 = ConstructorParameters<
new (x?: string) => object
>; // [x?: string | undefined]
它可以返回一些内置构造方法的参数类型。
type T1 = ConstructorParameters<
ErrorConstructor
>; // [message?: string]
type T2 = ConstructorParameters<
FunctionConstructor
>; // string[]
type T3 = ConstructorParameters<
RegExpConstructor
>; // [pattern:string|RegExp, flags?:string]
如果参数类型不是构造方法,就会报错。
type T1 = ConstructorParameters<string>; // 报错
type T2 = ConstructorParameters<Function>; // 报错
any类型和never类型是两个特殊值,分别返回unknown[]和never。
type T1 = ConstructorParameters<any>; // unknown[]
type T2 = ConstructorParameters<never>; // never
ConstructorParameters<Type>的实现如下。
type ConstructorParameters<
T extends abstract new (...args: any) => any
> = T extends abstract new (...args: infer P)
=> any ? P : never
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;
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;
InstanceType<Type>
InstanceType<Type>提取构造函数的返回值的类型(即实例类型),参数Type是一个构造函数,等同于构造函数的ReturnType<Type>。
type T = InstanceType<
new () => object
>; // object
由于 Class 作为类型,代表实例类型。要获取它的构造方法,必须把它当成值,然后用typeof运算符获取它的构造方法类型。
class C {
x = 0;
y = 0;
}
type T = InstanceType<typeof C>; // C
如果类型参数不是构造方法,就会报错。
如果类型参数是any或never两个特殊值,分别返回any和never。
type T1 = InstanceType<any>; // any
type T2 = InstanceType<never>; // never
InstanceType<Type>的实现如下。
type InstanceType<
T extends abstract new (...args:any) => any
> = T extends abstract new (...args: any) => infer R ? R :
any;
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类型。
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'>; // { }
指定删除的键名Keys可以是对象类型Type中不存在的属性,但必须兼容string|number|symbol。
Omit<Type, Keys>的实现如下。
type Omit<T, K extends keyof any>
= Pick<T, Exclude<keyof T, K>>;
OmitThisParameter<Type> # **
OmitThisParameter<Type>从函数类型中移除 this 参数。
function toHex(this: Number) {
return this.toString(16);
}
type T = OmitThisParameter<typeof toHex>; // () => string
如果函数没有 this 参数,则返回原始函数类型。
OmitThisParameter<Type>的实现如下。
type OmitThisParameter<T> =
unknown extends ThisParameterType<T> ? T :
T extends (...args: infer A) => infer R ?
(...args: A) => R : T;
Parameters<Type>
Parameters<Type>从函数类型Type里面提取参数类型,组成一个元组返回。
type T1 = Parameters<() => string>; // []
type T2 = Parameters<(s:string) => void>; // [s:string]
type T3 = Parameters<<T>(arg: T) => T>; // [arg: unknown]
type T4 = Parameters<
(x:{ a: number; b: string }) => void
>; // [x: { a: number, b: string }]
type T5 = Parameters<
(a:number, b:number) => number
>; // [a:number, b:number]
如果参数类型Type不是带有参数的函数形式,会报错。
由于any和never是两个特殊值,会返回unknown[]和never。
type T1 = Parameters<any>; // unknown[]
type T2 = Parameters<never>; // never
Parameters<Type>主要用于从外部模块提供的函数类型中,获取参数类型。
interface SecretName {
first: string;
last: string;
}
interface SecretSanta {
name: SecretName;
gift: string;
}
export function getGift(
name: SecretName,
gift: string
): SecretSanta {
// ...
}
type ParaT = Parameters<typeof getGift>[0]; // SecretName
type ReturnT = ReturnType<typeof getGift>; // SecretSanta
Parameters<Type>的实现如下。
type Parameters<T extends (...args: any) => any> =
T extends (...args: infer P)
=> any ? P : never
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];
};
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 }
指定的键名Keys必须是对象键名Type里面已经存在的键名,否则会报错。
Pick<Type, Keys>的实现如下。
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
Readonly<Type>
Readonly<Type>返回一个新类型,将参数类型Type的所有属性变为只读属性。
interface A {
x: number;
y?: number;
}
// { readonly x: number; readonly y?: number; }
type T = Readonly<A>;
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 = '李四'; // 报错
Record<Keys, Type>
Record<Keys, Type>返回一个对象类型,参数Keys用作键名,参数Type用作键值类型。
// { a: number }
type T = Record<'a', number>;
参数Keys可以是联合类型,这时会依次展开为多个键。
// { a: number, b: number }
type T = Record<'a'|'b', number>;
如果参数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; }
Required<Type>
Required<Type>返回一个新类型,将参数类型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];
};
ReadonlyArray<Type>
ReadonlyArray<Type>用来生成一个只读数组类型,类型参数Type表示数组成员的类型。
const values: ReadonlyArray<string>
= ['a', 'b', 'c'];
values[0] = 'x'; // 报错
values.push('x'); // 报错
values.pop(); // 报错
values.splice(1, 1); // 报错
interface ReadonlyArray<T> {
readonly length: number;
readonly [n: number]: T;
// ...
}
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<any>; // any
type T2 = ReturnType<never>; // never
ReturnType<Type>的实现如下。
type ReturnType<
T extends (...args: any) => any
> =
T extends (...args: any) => infer R ? R : any;
ThisParameterType<Type>
ThisParameterType<Type>提取函数类型中this参数的类型。
function toHex(this: Number) {
return this.toString(16);
}
type T = ThisParameterType<typeof toHex>; // number
如果函数没有this参数,则返回unknown。
ThisParameterType<Type>的实现如下。
type ThisParameterType<T> =
T extends (
this: infer U,
...args: never
) => any ? U : unknown;
ThisType<Type>
ThisType<Type>不返回类型,只用来跟其他类型组成交叉类型,用来提示 TypeScript 其他类型里面的this的类型。
let obj: ThisType<{ x: number }> &
{ getX: () => number };
obj = {
getX() {
return this.x + this.y; // 报错
},
};
使用这个类型工具时,必须打开noImplicitThis设置。
ThisType<Type>的实现就是一个空接口。
interface ThisType<T> { }
字符串类型工具
TypeScript 内置了四个字符串类型工具,专门用来操作字符串类型。这四个工具类型都定义在 TypeScript 自带的.d.ts文件里面。
它们的实现都是在底层调用 JavaScript 引擎提供 JavaScript 字符操作方法。
Uppercase<StringType>
Uppercase<StringType>将字符串类型的每个字符转为大写。
type A = 'hello';
// "HELLO"
type B = Uppercase<A>;
Lowercase<StringType>
Lowercase<StringType>将字符串的每个字符转为小写。
type A = 'HELLO';
// "hello"
type B = Lowercase<A>;
Capitalize<StringType>
Capitalize<StringType>将字符串的第一个字符转为大写。
type A = 'hello';
// "Hello"
type B = Capitalize<A>;
Uncapitalize<StringType>
Uncapitalize<StringType> 将字符串的第一个字符转为小写。
type A = 'HELLO';
// "hELLO"
type B = Uncapitalize<A>;