TypeScript `infer` 关键字


考察如下类型:

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]

相关资源

原文地址:https://www.cnblogs.com/Wayou/p/typescript_infer.html

时间: 2024-11-02 09:34:39

TypeScript `infer` 关键字的相关文章

typescripts学习

可选与默认参数 可选参数:在参数名后面,冒号前面添加一个问号,则表明该参数是可选的.如下代码: function buildName(firstName: string, lastName?: string) { //lastName为可选参数 if (lastName) return firstName + " " + lastName; else return firstName; } var result1 = buildName("Bob"); //正确调用

解读typescript中 super关键字的用法

传统的js,使用prototype实现父.子类继承.如果父.子类有同名的方法,子类去调用父类的同名方法需要用 “父类.prototype.method.call(this)”.但是在typescript中,提供了一个关键字super,指向父类.super.method() 这样就可以达到调用父类同名的方法. class Animal { constructor() { console.log('animal') } get() { console.log("吃饭") } } class

typescript的lambads解决this关键字找不到属性

var people = { name: ["abc", "jack", "pepter", "jim"], getname: function() { return function () { var i = Math.floor((Math.random() * 4)); return { n: this.name[i] }; }; } }; var myName = people.getname(); alert(&qu

【TypeScript】TypeScript 学习 5——方法

在 JavaScript 中,有两种方式定义方法. 1.命名的方法 function add(x,y){ return x+y; } 2.匿名方法 var myAdd = function(x,y) { return x+y;}; 在 TypeScript 中,也兼容上面两种定义方式,但是,既然我们用的是 TypeScript,那么肯定要强于本来的定义方式. 1.类型化方法 function add(x:number, y:number):number{ return x+y; } var my

TypeScript 素描 - 类

本文虽然是学自官方教程而来,但是也融入了自己的理解,而且对官方的例子做了一些修改 /* 类 面向对象编程的一大核心 使用C#.Java进行编程的朋友肯定已经是不能够再熟悉了 TypeScript的类与C#的类有着很高的相似度,但也有着些许不同 */ //构造函数不同,与类同名不再是构造函数而是方法 //构造函数则是constructor class Animal { //构造函数 constructor(public name: string) { this.name = name } //方法

TypeScript手册翻译系列7-泛型

泛型(Generics) 软件工程的一个主要部分是建立不仅有良好定义和一致性APIs,而且是可重用的组件(components).使用今天数据以及明日数据的组件才能够最为灵活地构建大规模软件系统. 在类似C#和Java等语言中,工具箱中创建可重用组件的一个主要工具就是泛型(generics),即能够创建可以使用各种类型而不是单一类型的组件.这使得用户可以用自己的类型来调用这些组件. Hello World of Generics 我们先来做一个泛型的"hello world":iden

TypeScript 基本语法

TypeScript 基本语法 TypeScript 是微软开发的 JavaScript 的超集,TypeScript兼容JavaScript,可以载入JavaScript代码然后运行.TypeScript与JavaScript相比进步的地方 包括:加入注释,让编译器理解所支持的对象和函数,编译器会移除注释,不会增加开销:增加一个完整的类结构,使之更新是传统的面向对象语言. TypeScript 微软官方网站 http://www.typescriptlang.org/TypeScript 源码

TypeScript学习指南第一章--基础数据类型

基础数据类型 为了搭建应用程序,我们需要使用一些基础数据类型比如:numbers,strings,structures,boolean等等. 在TypeScript中除了在JavaScript中常见的数据类型外还有一个非常使用的枚举类型(enumeration type). Boolean 最基础的数据类型莫过于只有True和false的布尔类型了,在TypeScript,JavaScript以及其它的很多数程序语言中我们使用关键字'boolean'. var isDone: boolean =

Angular基础(三) TypeScript

一.模仿Reddit a) 运行ng new –ng4angular-reddit创建应用,从随书代码中复制样式文件,新建组件app-root,代码为: 界面可以看到了: b) 对于界面输入的数据,获取的方式有点特别,使用了#newlink这样的语法,newlink是一个对象,现在代表就是所在的input这个DOM元素. 将对象作为参数传递给addArticle方法,在对应的ts代码中,可以获取newlink.value.newlink是HTMLInputElement类型. c)关于参数的绑定