还有这种骚操作?
enum METHOD {
DELETE = 'DELETE',
GET = 'GET',
HEAD = 'GET',
OPTIONS = 'OPTIONS',
PATCH = 'PATCH',
POST = 'POST',
PUT = 'PUT'
}
type TEST = {
[key in METHOD]: any;
};
非空断言
表明该值一定存在。
function test(param?: string[]): string {
return param!.join(' ');
}
类型化
Partial
把 interface 所有属性变成可选:
interface Obj {
a: number;
b: string;
}
type OptionalObj = Partial<Obj>
// interface OptionalObj {
// a?: number;
// b?: string;
// }
Readonly
把 interface 所有属性变成 readonly:
interface Obj {
a: number;
b: string;
}
type ReadonlyObj = Readonly<Obj>
// interface ReadonlyObj {
// readonly a: number;
// readonly b: string;
// }
Pick
获取类型中的若干项作为新的类型。
interface T {
a: string;
b: number;
c: boolean;
}
type OnlyAB = Pick<T, 'a' | 'b'>;
// interface OnlyAB {
// a: string;
// b: number;
// }
Record
该类型可以将 K
中所有的属性的值转化为 T
类型,源码实现如下:
// node_modules/typescript/lib/lib.es5.d.ts
type Record<K extends keyof any, T> = {
[P in K]: T;
};
复制代码
可以根据 K
中的所有可能值来设置 key,以及 value 的类型,举个例子:
type T11 = Record<'a' | 'b' | 'c', Person>; // -> { a: Person; b: Person; c: Person; }
Exclude
Exclude
将某个类型中属于另一个的类型移除掉。
源码的实现:
// node_modules/typescript/lib/lib.es5.d.ts
type Exclude<T, U> = T extends U ? never : T;
复制代码
以上语句的意思就是 如果 T
能赋值给 U
类型的话,那么就会返回 never
类型,否则返回 T
,最终结果是将 T
中的某些属于 U
的类型移除掉,举个例子:
type T00 = Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'>; // -> 'b' | 'd'
复制代码
可以看到 T
是 'a' | 'b' | 'c' | 'd'
,然后 U
是 'a' | 'c' | 'f'
,返回的新类型就可以将 U
中的类型给移除掉,也就是 'b' | 'd'
了。
Extract
Extract
的作用是提取出 T
包含在 U
中的元素,换种更加贴近语义的说法就是从 T
中提取出 U
,源码如下:
// node_modules/typescript/lib/lib.es5.d.ts
type Extract<T, U> = T extends U ? T : never;
复制代码
以上语句的意思就是 如果 T
能赋值给 U
类型的话,那么就会返回 T
类型,否则返回 never
,最终结果是将 T
和 U
中共有的属性提取出来,举个例子:
type T01 = Extract<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'>; // -> 'a' | 'c'
复制代码
可以看到 T
是 'a' | 'b' | 'c' | 'd'
,然后 U
是 'a' | 'c' | 'f'
,返回的新类型就可以将 T
和 U
中共有的属性提取出来,也就是 'a' | 'c'
了。
ReturnType
获取函数返回值。
function abc(): 'a' | 'b' | 'c' {
return 'a';
}
const def: () => 'd' | 'e' | 'f' = () => {
return 'd';
};
type a = ReturnType<typeof abc>; // 'a' | 'b' | 'c'
type d = ReturnType<typeof def>; // 'd' | 'e' | 'f'
ThisType
这个类型是用于指定上下文对象类型的。
// node_modules/typescript/lib/lib.es5.d.ts
interface ThisType<T> { }
复制代码
可以看到声明中只有一个接口,没有任何的实现,说明这个类型是在 TS 源码层面支持的,而不是通过类型变换。
这类型怎么用呢,举个例子:
interface Person {
name: string;
age: number;
}
const obj: ThisType<Person> = {
dosth() {
this.name // string
}
}
复制代码
这样的话,就可以指定 obj
里的所有方法里的上下文对象改成 Person
这个类型了。
InstanceType
该类型的作用是获取构造函数类型的实例类型。
源码实现:
// node_modules/typescript/lib/lib.es5.d.ts
type InstanceType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer R ? R : any;
复制代码
看一下官方的例子:
class C {
x = 0;
y = 0;
}
type T20 = InstanceType<typeof C>; // C
type T21 = InstanceType<any>; // any
type T22 = InstanceType<never>; // any
type T23 = InstanceType<string>; // Error
type T24 = InstanceType<Function>; // Error
复制代码
NonNullable
这个类型可以用来过滤类型中的 null
及 undefined
类型。
源码实现:
// node_modules/typescript/lib/lib.es5.d.ts
type NonNullable<T> = T extends null | undefined ? never : T;
复制代码
比如:
type T22 = string | number | null;
type T23 = NonNullable<T22>; // -> string | number;
复制代码
Parameters
该类型可以获得函数的参数类型组成的元组类型。
源码实现:
// node_modules/typescript/lib/lib.es5.d.ts
type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
复制代码
举个栗子:
function foo(x: number): Array<number> {
return [x];
}
type P = Parameters<typeof foo>; // -> [number]
复制代码
此时 P
的真实类型就是 foo
的参数组成的元组类型 [number]
。
ConstructorParameters
该类型的作用是获得类的参数类型组成的元组类型,源码:
// node_modules/typescript/lib/lib.es5.d.ts
type ConstructorParameters<T extends new (...args: any[]) => any> = T extends new (...args: infer P) => any ? P : never;
复制代码
举个栗子:
class Person {
private firstName: string;
private lastName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
}
type P = ConstructorParameters<typeof Person>; // -> [string, string]
复制代码
此时 P
就是 Person
中 constructor
的参数 firstName
和 lastName
的类型所组成的元组类型 [string, string]
。
Omit
有时候我们想要继承某个接口,但是又需要在新接口中将某个属性给 overwrite 掉,这时候通过 Pick
和 Exclude
就可以组合出来 Omit
,用来忽略对象某些属性功能:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
// 使用
type Foo = Omit<{name: string, age: number}, 'name'> // -> { age: number }
复制代码
Mutable
将 T 的所有属性的 readonly
移除:
type Mutable<T> = {
-readonly [P in keyof T]: T[P]
}
复制代码
PowerPartial
内置的 Partial 有个局限性,就是只支持处理第一层的属性,如果是嵌套多层的就没有效果了,不过可以如下自定义:
type PowerPartial<T> = {
// 如果是 object,则递归类型
[U in keyof T]?: T[U] extends object
? PowerPartial<T[U]>
: T[U]
};
复制代码
Deferred
相同的属性名称,但使值是一个 Promise
,而不是一个具体的值:
type Deferred<T> = {
[P in keyof T]: Promise<T[P]>;
};
复制代码
Proxify
为 T
的属性添加代理
type Proxify<T> = {
[P in keyof T]: { get(): T[P]; set(v: T[P]): void }
};
复制代码
Depromise
抹去 Promise
外包装,获取泛型值。
declare function test(): Promise<string>;
type Temp = ReturnType<typeof test> extends Promise<infer R> ? R : ReturnType<typeof test>; // string
封装,可得:
declare function test(): Promise<string>;
// 初始封装
type PickPromise<T> = T extends Promise<infer R> ? R : T;
type Temp = PickPromise<ReturnType<typeof test>>; // string
// 完整封装,指明 T 是函数类型
type PickPromiseFromReturnType<T extends (...args: any) => any> = ReturnType<T> extends Promise<infer R> ? R : ReturnType<T>;
type Temp = PickPromiseFromReturnType<typeof test>; // string