TypeScript泛型工具

304 阅读4分钟

前提知识点: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 Keys and whose property values are Type. 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;

总结

对于我们的日常开发工作,其实确实会使用很多的泛型工具去编写类型以及类型工具,但我们在编写的过程中,也要注意。

  • 特定的泛型工具的逻辑是如何实现的?
  • 是否可以结合已有的泛型工具编写自己需要的泛型工具?
  • 写的泛型工具是否对业务或开发有所意义?(不要为了写类型而写类型)

参考与推荐