Typescript 的 Infer 怎么用?

440 阅读2分钟

TS 提供了很多高级的类型,来帮助我们灵活得进行类型编程,其中 Infer 可以通过占位符的方式,匹配(获取)传入类型中 我们需要的部分类型。

举个🌰:

下面是一个人类类,我想要获取构造函数的类型

class People {
    public name: string;
    public age: number;
    constructor(name: string, age: number) {
        this.name = name
        this.age = age;
    }
}

在下面的代码中,我用infer P 占了一个位置来获取函数类型的参数类型。

要注意的是,infer 要和 extends 放在一起用,通过 三元运算符,来获取类型 P。

type ConstructorParamsType<T> = T extends new(...args: infer P) => any ? P :never;

let constructorParameters: ConstructorParamsType<new (name: string, classno: number) => any>

如下图:获取到了传入函数类型的参数类型

image.png

在下面的代码中,我用infer P 占了一个位置来获取函数类型的返回值类型。

type ConstructorParamsType<T> = T extends new(...args: any) => infer P ? P :never;

let constructorParameters: ConstructorParamsType<new (name: string, classno: number) => string>

如下图:获取到了传入函数类型的返回参数

image.png

那么如果我想要获取人类类型的构造函数的参数,就可以用 typeof People来传入人类类的构造函数类型。

type ConstructorParamsType<T> = T extends new(...args: infer P) => any ? P :never;

let constructorParameters: ConstructorParamsType<typeof People>

如下图:获取到了人类类构造函数的参数 image.png

案例:带参数检测的泛型工厂函数

现在我们要创建一个泛型工厂函数,并且带着参数检测。

首先创建一个泛型工厂函数,但是这个工厂函数不能做传入的类型检查。

type Constructor<T> = new (...args: any[]) => T // 约束传入一个类

function createInstance<T>(constructor: Constructor, ...args: any[]) { // 泛型工厂函数
    return new constructor(...args);
} 

createInstance(People, "小明"18); // 运行

为了能够做类型检查,我们采用infer获取它的构造函数参数类型。

type Constructor<T> = new (...args: any[]) => T // 约束传入一个类

type ConstructorParamsType<T> = T extends new(...args: infer P) => any ? P :never; // 获取传入构造函数类型中的参数类型

// 约束 P 传入的是一个构造函数类型
function createInstance<T, P extends new (...args: any[]) => any> 
(constructor: Constructor<T>, ...args: ConstructorParamsType<P>) { // 泛型工厂函数
    return new constructor(...args);
} 


createInstance<People, typeof People>(People, "小明", 18); // 运行

如下图:此时就会检测到参数传入错误。

image.png