前提知识点:
TypeScript的基础,泛型,类型编程的概念。
前言
我们在学习TypeScript中,我们有学习到泛型的概念,其中,比较常见的如Array<T>、Promise<T>等,我们借助这些泛型,我们可以去产生新的类型。
泛型,通用的类型,给了类型系统增加了一定的灵活性。
同时,TypeScript中,有内置一些泛型工具,提供我们做类型转换。下面,我们就拿几个常见的进行介绍,并且我们也来手写实现一下。
常见泛型工具
Partial<Type>
这个泛型工具可以将接口类型的中的属性全部转换成可选属性。
例子
上面,我们可以看到当我们使用Partial,会对传入的类型属性全部变成可选
实现
type MyPartial<T> = {
[K in keyof T]?: T[K];
}
type PartialStudent = MyPartial<Student>;
Required<Type>
这个泛型工具可以将接口类型中的属性全部转换成必选属性。
例子
上述的可选属性全部变成了必选属性。
实现
type MyRequired<T> = {
[K in keyof T]-?: T[K];
}
Readonly<Type>
当我们用readonly修饰接口中的属性的时候,表明该变量是不可修改,当我们对其进行赋值修改的时候,
TypeScript会在编译阶段将其暴露出来。、
该工具可将将接口类型中的属性全部转换成只读属性。
例子
下面,我们使用Readonly产出新的类型,并新建了一个变量,尝试修改属性,结果如图。
实现
type MyReadonly<T> = {
readonly [Key in keyof T]: T[Key];
};
Record<Keys, Type>
Constructs an object type whose property keys are
Keysand whose property values areType. This utility can be used to map the properties of a type to another type.
构建一个对象类型,其中属性为Key类型的会对应Type类型,我们常见的有Record<string, any>, Record<string, string>等。
例子
我们来实现一个StringMap类型。
实现
通过 K extends keyof any 对泛型进行约束,约束在 any 的 key中, K可以是任意类型(联合类型、对象、枚举…),再通过映射对象类型 { P in K : T } ,将每一个属性成员转化为 T 类型
type MyRecord<K extends keyof any, T> = {
[P in K]: T;
};
Pick<Type, Keys>
映射类型的语法用于构造新的索引类型,在构造的过程中可以对索引和值做一些修改或过滤。
例子
使用pick,我们可以简单提取其中我们需要的属性。
实现
这里我们是要提供两个泛型传入,一个是我们要作用的对象类型,一个是我们需要提取的键值。
注意,这里的K泛型参数,使用了
extends进行了类型约束。这样子。当我们使用Pick的时候,输入我们需要提取的键名的时候,会有更良好的提示。
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
}
Parameters<Type>
这个工具主要适用于函数,能够提取函数所需要的参数类型。
例子
实现
这里使用了条件类型进行类型约束(收敛为函数),同时使用infer去推导函数的参数。
type MyParameters<T extends Function> =
T extends (...args: infer R) => any ?
R : never;
ReturnType<Type>
这个工具主要适用于函数,能够提取函数所返回的类型。
例子
实现
这里使用了条件类型进行类型约束(收敛为函数),同时使用infer去推导函数的返回值。
type MyReturnType<T extends Function> =
T extends (...args: any[]) => infer R ?
R : never;
扩展
TypeScript内置的泛型工具给我们提供了很多的便利。当然,我们也可以基于泛型工具去进行自己的泛型工具的编写。(TS的灵活之处也在于能支持类型编程。)
举个例子,我们可以编写一个得到Promise中返回类型的泛型工具
type GetPromiseValueType<P> = P extends Promise<infer Value> ? Value : never;
总结
对于我们的日常开发工作,其实确实会使用很多的泛型工具去编写类型以及类型工具,但我们在编写的过程中,也要注意。
- 特定的泛型工具的逻辑是如何实现的?
- 是否可以结合已有的泛型工具编写自己需要的泛型工具?
- 写的泛型工具是否对业务或开发有所意义?(不要为了写类型而写类型)