TypeScript 类型工具
TypeScript 提供了一些内置的类型工具,用来方便地处理各种类型,以及生成新的类型。
这些类型工具都是语言本身提供的,可以直接使用。
Awaited<Type>
Awaited<Type>用来取出 Promise 的返回值类型,适合用在描述then()方法和 await 命令的参数类型。
// string
type A = Awaited<Promise<string>>;
上面示例中,Awaited<Type>会返回 Promise 的返回值类型(string)。
它也可以返回多重 Promise 的返回值类型。
// number
type B = Awaited<Promise<Promise<number>>>;
如果它的类型参数不是 Promise 类型,那么就会原样返回。
// number | boolean
type C = Awaited<boolean | Promise<number>>;
上面示例中,类型参数是一个联合类型,其中的boolean会原样返回,所以最终返回的是number|boolean。
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<V> : 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;
上面代码中,等号右边的部分,表示先判断T是否兼容U,如果是的就返回never类型,否则返回当前类型T。由于never类型是任何其他类型的子类型,它跟其他类型组成联合类型时,可以直接将never类型从联合类型中“消掉”,因此Exclude<T, U>就相当于删除兼容的类型,剩下不兼容的类型。
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
上面示例中,类型参数是一个构造函数new () => object,返回值是该构造函数的实例类型(object)。
下面是一些例子。
type A = InstanceType<ErrorConstructor>; // Error
type B = InstanceType<FunctionConstructor>; // Function
type C = InstanceType<RegExpConstructor>; // RegExp
上面示例中,InstanceType<T>的参数都是 TypeScript 内置的原生对象的构造函数类型,InstanceType<T>的返回值就是这些构造函数的实例类型。
由于 Class 作为类型,代表实例类型。要获取它的构造方法,必须把它当成值,然后用typeof运算符获取它的构造方法类型。
class C {
x = 0;
y = 0;
}
type T = InstanceType<typeof C>; // C
上面示例中,typeof C是C的构造方法类型,然后 InstanceType 就能获得实例类型,即C本身。
如果类型参数不是构造方法,就会报错。
type T1 = InstanceType<string>; // 报错
type T2 = InstanceType<Function>; // 报错
如果类型参数是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