您的位置:首页 > Web前端

TypeScript `infer` 关键字

Wayou 2019-05-28 23:39 281 查看 https://www.cnblogs.com/wayou/

考察如下类型:

type PromiseType<T> = (args: any[]) => Promise<T>;

那么对于符合上面类型的一个方法,如何得知其 Promise 返回的类型?

譬如对于这么一个返回

string
类型的 Promise:

async function stringPromise() {
return "string promise";
}

RetrunType

如果你对 TypeScript 不是那么陌生,可能知道官方类型库中提供了

RetrunType
可获取方法的返回类型,其用法如下:

type stringPromiseReturnType = ReturnType<typeof stringPromise>; // Promise<string>

确实拿到了方法的返回类型,不过是

Promise<string>
。但其实是想要返回里面的
string
,所以和我们想要的还差点意思。

既然都能从一个方法反解其返回类型,肯定还能从

Promsie<T>
中反解出
T
。所以不不妨看看
ReturnType
的定义:

/**
* Obtain the return type of a function type
*/
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

F12 一看,果然发现了点什么,这里使用了

infer
关键字。

条件类型及
infer

上面

T extends U ? X : Y
的形式为条件类型(Conditional Types),即,如果类型
T
能够赋值给类型
U
,那么该表达式返回类型
X
,否则返回类型
Y

所以,考察

ReturnType
的定义,

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

如果传入的类型

T
能够赋值给
(...args: any) => R
则返回类型
R

但是这里类型

R
从何而来?讲道理,泛型中的变量需要外部指定,即
RetrunType<T,R>
,但我们不是要得到 R 么,所以不能声明在这其中。这里
infer
便解决了这个问题。表达式右边的类型中,加上
infer
前缀我们便得到了反解出的类型变量
R
,配合
extends
条件类型,可得到这个反解出的类型
R
。这里
R
即为函数
(...args: any) => R
的返回类型。

反解 Promise

有了上面的基础,推而广之就很好反解

Promise<T>
中的
T
了。

type PromiseType<T> = (args: any[]) => Promise<T>;

type UnPromisify<T> = T extends PromiseType<infer U> ? U : never;

测试

UnPromisify<T>

async function stringPromise() {
return "string promise";
}

async function numberPromise() {
return 1;
}

interface Person {
name: string;
age: number;
}

async function personPromise() {
return { name: "Wayou", age: 999 } as Person;
}

type extractStringPromise = UnPromisify<typeof stringPromise>; // string

type extractNumberPromise = UnPromisify<typeof numberPromise>; // number

type extractPersonPromise = UnPromisify<typeof personPromise>; // Person

解析参数数组的类型

反解还可用在其他很多场景,比如解析函数入参的类型。

type VariadicFn<A extends any[]> = (...args: A) => any;
type ArgsType<T> = T extends VariadicFn<infer A> ? A : never;

type Fn = (a: number, b: string) => string;
type Fn2Args = ArgsType<Fn>; // [number, string]

相关资源

标签: