TypeScript中的隐藏神器 ———— infer

181 阅读3分钟

前言

关于infer的简介:

  • 官方解释

    现在在有条件类型的 extends 子语句中,允许出现 infer 声明,它会引入一个待推断的类型变量。 这个推断的类型变量可以在有条件类型的 true 分支中被引用。 允许出现多个同类型变量的 infer。

只需要记住

  • 只能出现在有条件类型extends的子语句中
  • 引入infer会出现一个待推断的变量
  • 推断的变量只能在truef分支中被引用 通俗的来说:想要获取哪块的变量类型就在哪里用infer标注这个类型

结合实际范例理解一下?

1. 获取函数的参数类型(Parameters)

  • 比如我们这里想把函数fn的参数类型取出来,该怎么办?

    function fn1(width: number, height: number): number {
            return width + height;
    }
    
  • 我们可以

    type getFuncParamsType<T> = T extends (...args: infer P) => any ? P : T;//声明一个getFuncParamsType<T>类型,此类型接收一个泛型参数
    type a = getFuncParamsType<typeof fn1>;
    

    image.png

整个过程呢,你可以简单的理解为getFuncParamsType接受一个泛型,如果T类型能被赋值给(...args:infer p) => any 则返回P,否则返回T

悄悄告诉你,其实ts中也内置了这个类型,名字叫Parameters<T>,平时项目中你可以直接用。

由此,我们可以知道,关于infer

  • 只能出现在有条件类型extends的子语句中
  • 引入infer会出现一个待推断的变量
  • 推断的变量只能在truef分支中被引用 通俗的来说:想要获取哪块的变量类型就在哪里用infer标注这个类型

我们经过上面的分析,下面的如何获取函数返回值类型,是不是已经呼之欲出了。

2. 获取函数的返回值类型(ReturnType)

function fn2(): boolean {
	return true;
}

type getFuncReturnType<T> = T extends () => infer P ? P : T;
type a = getFuncReturnType<typeof fn2>;

整个过程你可以这样理解,我们声明了一个类型getFuncReturnType<T>类型,然后我们想获取函数的返回值的类型,我们就将infer P标成函数的返回值,如果为T类型可以赋值给() => infer P直接返回P,否则直接返回T

该方法,ts已内置,名字叫ReturnType<T>

3. 获取构造函数参数类型(ConstructorParameters)

我们想获取构造函数的参数类型,是不是只要把infer P标注在构造函数参数的位置就可以

class People {
	name: string;
	constructor(name: string) {
		this.name = name;
	}
}
type GetContructor<T> = T extends new (...args: infer P) => any ? P : T;
type a = GetContructor<typeof People>;

image.png

该方法,ts已内置,名字叫ConstructorParameters<T>

4. 获取实例类型(InstanceType)

我们想获取构造函数People的实例类型

class People {
	name: string;
	constructor(name: string) {
		this.name = name;
	}
}
type GetInstanceType<T> = T extends new (...args: any) => infer P ? P : never;
type a = GetInstanceType<typeof  People>;

image.png

该方法,ts已内置,名字叫InstanceType<T>

5. 获取this参数的类型(ThisParameterType)

我们想获取fn1函数的this类型。

function fn1(this: { name: string; age: number }) {
	this.name = "杨志强";
	this.age = 23;
}
type GetFuncThisType<T> = T extends (this: infer P, ...args: any) => any ? P : T;
type a = GetFuncThisType<typeof fn1>;

image.png

该方法,ts已内置,名字叫ThisParameterType<T>

6. 剔除this参数(OmitThisParameter)

type OmitThisParameter<T> = unknown extends ThisParameterType<T> 
? T 
: T extends (...args: infer A) => infer R 
? (...args: A) => R 
: T;

以下语法是判断是否包含this参数。

unknown extends ThisParameterType<T> 

实战中积累的infer用法

1.判断俩个类型是否相同?

type isEqual<T, U> = ((p1: T, p2: U) => void) extends ((...args: infer P) => void) ? P[number] extends T ? true : false : false;
type a = ["a"];
type b = [1];
type res = isEqual<a, b>;

image.png

我们可以这样理解:类型isEqual接受俩个泛型,利用infer的特性得到参数类型是一个数组,再取出下标为number的每一项,组成一个联合类型,接着看获取到的联合类型能否赋值给TU也可以),从而就可以判断是否为相同类型。