学习 TypeScript 到必定阶段,必需要学会高阶类型的使用,不然一些复杂的场景如果用 any
类型来处理的话,也就失去了 TS 类型检查的意义。html
本文罗列了 TypeScript 经常使用的高阶类型,包含 官方 、以及 经常使用的非官方 的高级类型声明,该手册直接硬啃的话有些枯燥,适合平时快速查阅,使用 Ctrl+F
来查找关键词来定位便可。node
交叉类型是将 多个类型合并为一个类型。 这让咱们能够把现有的多种类型叠加到一块儿成为一种类型,它包含了所需的全部类型的特性。git
Person & Serializable & Loggable
示例:extend
融合方法github
function extend<T, U>(first: T, second: U): T & U { let result = <T & U>{}; for (let id in first) { (<any>result)[id] = (<any>first)[id]; } for (let id in second) { if (!result.hasOwnProperty(id)) { (<any>result)[id] = (<any>second)[id]; } } return result; }
特殊状况:
T | never = T
T & never = never (which #16446 provides)typescript
T extends U ? X : Y
表示,若是 T 能够赋值给 U (类型兼容),则返回 X,不然返回 Y;数组
keyof
和 in
keyof
能够用来取得一个对象接口的全部 key 值:微信
interface Foo { name: string; age: number } type T = keyof Foo // -> "name" | "age"
而 in
则能够遍历枚举类型, 例如:ide
type Keys = "a" | "b" type Obj = { [p in Keys]: any } // -> { a: any, b: any }
keyof
产生联合类型, in
则能够遍历枚举类型, 因此他们常常一块儿使用。函数
infer
关键字infer
这个关键字是在 TS 2.8 版本引入的, 在条件类型语句中,该关键字用于替代手动获取类型。工具
TypeScript 为此提供了一个示例,他们建立了一个叫做 Flatten
的类型,用于将数组转成他们须要的元素类型:
type Flatten<T> = T extends any[] ? T[number] : T;
若是使用关键字 infer 就能够将上面的代码简化成:
type Flatten<T> = T extends Array<infer U> ? U : T;
做用:将传入的属性变为可选项
源码:
type Partial<T> = { [P in keyof T]?: T[P] };
解释:
keyof T
拿到 T
全部属性名in
进行遍历, 将值赋给 P
, 最后 T[P]
取得相应属性的值.?
咱们就明白了 Partial 的含义了.扩展:内置的 Partial
有个局限性,就是只支持处理第一层的属性,若是是嵌套多层的就没有效果了,不过能够以下自定义:
type PowerPartial<T> = { // 若是是 object,则递归类型 [U in keyof T]?: T[U] extends object ? PowerPartial<T[U]> : T[U] };
做用:将传入的属性变为必选项
源码:
type Required<T> = { [P in keyof T]-?: T[P] };
解释:
-?
, 这里很好理解就是将可选项表明的 ?
去掉, 从而让这个类型变成必选项+?
, 这个含义天然与 -?
以前相反, 它是用来把属性变成可选项的做用:将传入的属性变为只读选项
源码:
type Readonly<T> = { readonly [P in keyof T]: T[P] };
扩展:在 巧用 Typescript 中,做者建立了 DeepReadonly
的声明,使用 递归 的思想让任何子属性都不可更改
type DeepReadonly<T> = { readonly [P in keyof T]: DeepReadonly<T[P]>; } const a = { foo: { bar: 22 } } const b = a as DeepReadonly<typeof a> b.foo.bar = 33 // Hey, stop!
做用:将 T
的全部属性的 readonly
移除
源码:
type Mutable<T> = { -readonly [P in keyof T]: T[P] }
解释:
+
和 -
, 进行的不是变量的之间的进行加减而是对 readonly
属性进行加减做用:将 K
中全部的属性的值转化为 T
类型
源码:
type Record<K extends keyof any, T> = { [P in K]: T };
示例:
// 对全部 T 类型的属性 K, 将它转换为 U function mapObject<K extends string | number, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>; const names = { foo: "hello", bar: "world", baz: "bye" }; const lengths = mapObject(names, s => s.length); // { foo: number, bar: number, baz: number }
做用:从 T 中取出 一系列 K 的属性
源码:
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
示例:
// 从 T 挑选一些属性 K declare function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K>; const nameAndAgeOnly = pick(person, "name", "age"); // { name: string, age: number }
某些地方也称为
Diff
做用:从 T
中剔除能够赋值给 U
的类型,换言之就是从T
中排除 U
源码:
type Exclude<T, U> = T extends U ? never : T;
解释:
T extends U ? X : Y
表示若是 T
是 U
的子类型的话,那么就会返回 X
,不然返回 Y
T extends U ? X : Y
, T
多是 A | B
的联合类型, 那实际状况就变成(A extends U ? X : Y) | (B extends U ? X : Y)
示例:
type T = Exclude<1 | 2, 1 | 3> // -> 2
参考文档:
做用:从 T
中提取出包含在 U
的类型,换言之就是从T
中提取出 U
子集
源码:
type Extract<T, U> = T extends U ? T : never;
示例:
type T = Extract<1 | 2, 1 | 3> // -> 1
做用:从 T
中忽略在 K
中的属性名 ,实现忽略对象某些属性功能,多在高阶组件中使用
源码:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
示例:
type Foo = Omit<{name: string, age: number}, 'name'> // -> { age: number }
做用: T
中的定义被在 K
中的内容所覆盖,多在高阶组件中使用,内部借助 Diff 操做实现
源码:
type Overwrite<T, U> = { [P in Exclude<keyof T, keyof U>]: T[P] } & U;
示例:
type Item1 = { a: string, b: number, c: boolean }; type Item2 = { a: number }; type T3 = Overwrite<Item1, Item2> // { a: number, b: number, c: boolean };
做用:从 T
中忽略在 K
中的属性名 ,实现忽略对象某些属性功能,多在高阶组件中使用
源码:
type ReturnType<T> = T extends ( ...args: any[] ) => infer R ? R : any;
解释:
infer
声明一个类型变量,是用它获取函数的返回类型,简单说就是用它取到函数返回值的类型方便以后使用.示例:
function foo(x: number): Array<number> { return [x]; } type fn = ReturnType<typeof foo>;
做用:用于指定上下文对象类型的
源码:
// node_modules/typescript/lib/lib.es5.d.ts interface ThisType<T> { }
解释:
示例:
interface Person { name: string; age: number; } const obj: ThisType<Person> = { dosth() { this.name // string } }
这样的话,就能够指定 obj
里的全部方法里的上下文对象改为 Person
这个类型了
做用:用于获取构造函数类型的实例类型
源码:
// 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;
解释:
infer
和 extends
条件判断完成示例:
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
这样的话,就能够指定 obj
里的全部方法里的上下文对象改为 Person
这个类型了
做用:这个类型能够用来过滤类型中的 null 及 undefined 类型。
源码:
// node_modules/typescript/lib/lib.es5.d.ts type NonNullable<T> = T extends null | undefined ? never : T;
解释:
extends
条件判断完成示例:
type T22 = string | number | null; type T23 = NonNullable<T22>; // -> string | number;
做用:该类型能够得到函数的参数类型组成的元组类型。
源码:
// node_modules/typescript/lib/lib.es5.d.ts type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
解释:
infer
和 extends
条件判断完成示例:
function foo(x: number): Array<number> { return [x]; } type P = Parameters<typeof foo>; // -> [number]
此时 P
的真实类型就是 foo
的参数组成的元组类型 [number]
做用:得到类的参数类型组成的元组类型。
源码:
// 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;
解释:
infer
和 extends
条件判断完成示例:
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]
。
下面的是个人公众号二维码图片,欢迎关注。