首先从一个问题引入,下面有一个模拟发送请求的方法,返回内容被包裹在 Promise 里面返回,我们怎样拿到 Promise 里面包裹的类型呢?

type ResponseEntity<T> = {success: boolean;result: T | null;message: string;
}function request<T>(req: T, timeout: number) {return Promise.race([new Promise<ResponseEntity<T>>(resolve => setTimeout(() => resolve({success: true,result: req,message: ""}), 3000)),new Promise<ResponseEntity<T>>((_, reject) => setTimeout(() => reject({success: false,result: null,message: "请求超时"}), timeout))])
}

很多同学上来就用 typeofReturnType 一把梭哈:

type Request = typeof request; // type Request = <T>(req: T, timeout: number) => Promise<ResponseEntity<T>>
type ReturnRequest = ReturnType<Request>; // type ReturnRequest = Promise<ResponseEntity<unknown>>

这样搞了之后最终只能拿到返回类型 Promise<ResponseEntity<unknown>> ,对于 Promise 里面的泛型参数就无能为力了。这个时候就要用到 infer 关键字进行类型推断。

所谓推断,就是你不用预先指定在泛型列表中,在运行时会自动判断,不过你得先预定义好整体的结构。举个例子

type Foo<T> = T extends {t: infer Test} ? Test: string

首选看 extends 后面的内容,{t: infer Test} 可以看成是一个包含 t 属性的类型定义,这个 t 属性的 value 类型通过 infer 进行推断后会赋值给 Test 类型,如果泛型实际参数符合 {t: infer Test} 的定义那么返回的就是 Test 类型,否则默认给缺省的 string 类型。

举个例子加深下理解

type One = Foo<number>  // string,因为number不是一个包含t的对象类型
type Two = Foo<{t: boolean}>  // boolean,因为泛型参数匹配上了,使用了infer对应的type
type Three = Foo<{a: number, t: () => void}> // () => void,泛型定义是参数的子集,同样适配

使用 infer 实际上就是定义了一个泛型函数,通过传入类型参数,然后返回指定的类型。infer 用来对满足的泛型类型进行子类型的抽取,有很多高级的泛型工具也巧妙的使用了这个方法。

回到最开始的问题,我们定义一个 infer 结构:

type Awaited<T> = T extends Promise<infer U> ? U : T;

然后给这个结构传入实际参数:

type Res = Awaited<ReturnRequest>;
/*** type Res = {*  success: boolean;*  result: unknown;*  message: string;* }*/

这样我们就拿到了 Promise 内部的泛型参数。

再说一下 TS如何获取第三方库未导出的 Type 这篇文章中的问题,获取函数参数,我们使用了 Parameters<T> ,这样得到的是一个函数参数类型的元组,还得通过下标去拿对应的类型,感觉不是很优雅:

type RadioProps = React.ComponentProps<typeof Radio.Group>;
type ChangeEvent = RadioProps["onChange"];
type ChangeFnParams = Parameters<NonNullable<ChangeEvent>>[0];

看了一下 Parameters<T> 的定义:

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

可以看到 args 的类型是一个数组,因此推断出来的是一个参数类型的元组。我们希望在只有一个参数的时候直接拿到类型,因此改写了 Parameters<T> 的定义如下:

type Param<T> = T extends (arg: infer U) => any ? U : never;

这样就可以直接取到参数类型了:

type RadioProps = React.ComponentProps<typeof Radio.Group>;
type ChangeEvent = RadioProps["onChange"];
type Param<T> = T extends (args: infer U) => any ? U : never;
type ChangeFnParams = Param<NonNullable<ChangeEvent>>; // type ChangeFnParams = RadioChangeEvent

顺便说一下 TS 内置的工具类型是怎么做的,ReturnType 是这样定义的:

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

Parameters 的定义如下:

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

ConstructorParameters 定义如下:

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

参考:

TypeScript 高级用法

TypeScript 使用 infer 实现类型推断相关推荐

  1. TypeScript Type Innference(类型推断)

    在这一节,我们将介绍TypeScript中的类型推断.我们将会讨论类型推断需要在何处用到以及如何推断. 基础 在TypeScript中,在几个没有明确指定类型注释的地方将会使用类型推断来提供类型信息. ...

  2. Typescript 类型推断

    TypeScript 能根据一些简单的规则推断(检查)变量的类型,你可以通过实践,很快的了解它们. #定义变量 变量的类型,由定义推断: `let foo = 123; // foo 是 'numbe ...

  3. 使用TypeScript映射和条件类型使React组件更出色

    by Deepu K Sasidharan 通过Deepu K Sasidharan 使用TypeScript映射和条件类型使React组件更出色 (Make your React component ...

  4. java全局变量和局部变量_Java 10 –局部变量类型推断

    java全局变量和局部变量 在本文中,我们将看到作为JEP 286的一部分提出的名为Local Variable Type Inference的Java10功能. 从Java的第一个版本开始,它是一种 ...

  5. java 鲜为人知的知识点_鲜为人知的Java 8功能:广义目标类型推断

    java 鲜为人知的知识点 遍历Java 8的功能列表 , 广义目标类型推断使我震惊,因为它是一个特别有趣,鲜为人知的瑰宝. 看起来Java语言设计人员将减轻过去使用泛型(Java 5-7)时遇到的某 ...

  6. Java 10 –局部变量类型推断

    在本文中,我们将看到作为JEP 286的一部分提出的名为Local Variable Type Inference的Java10功能. 从Java的第一个版本开始,它是一种强类型语言,在这里我们需要提 ...

  7. 鲜为人知的Java 8功能:广义目标类型推断

    遍历Java 8功能列表 , 广义目标类型推断使我震惊,因为它是一个特别有趣,鲜为人知的瑰宝. 看起来Java语言设计人员将减轻过去使用泛型(Java 5-7)时遇到的某些痛苦. 让我们看看他们的例子 ...

  8. 第七节:在 TypeScript 中什么是类型推论?

    上一节,我们学习了TypeScript中的一种新的数据类型:元组Tuple.没学习上一节的同学可以戳:<又一种新的数据类型:元组Tuple> 这一节,我们一起来学习一下TypeScript ...

  9. matlab中float类型的_Java局部变量类型推断(Var类型)的26条细则

    原文链接:https://dzone.com/articles/var-work-in-progress 作者:Anghel Leonard 译者:沈歌 Java局部变量类型推断(LVTI),简称 v ...

  10. Java 10:局部变量类型推断

    Java 10:局部变量类型推断 在本文中,我们将深入研究Java 10中引入的局部变量类型推断的新特性.我们将讨论使用局部变量类型推断的范围和局限性. 此功能是作为JEP(JDK增强提案)的一部分提 ...

最新文章

  1. C++中的STL算法详解
  2. Dagger2从入门到熟练
  3. 如何用 ajax 连接mysql数据库,并且获取从中返回的数据。ajax获取从mysql返回的数据。responseXML分别输出不同数据的方法。...
  4. leetcode 506. 相对名次(Java版)
  5. html表单实验总结,HTML表单总结
  6. Ngs File Type Transfer
  7. linux 驱动线程与进程,Linux内核学习之二-进程与线程
  8. 004 Leaflet 第四个demo 使用自己的图标替换marker图标
  9. win10 修改进入 cmd 命令行的默认路径
  10. 一、Java语言基础(5)_数组高级——方法参数的值传递机制
  11. try-catch(C# 参考)
  12. QCustomplot绘图性能的改善
  13. php自动发卡程序8.0_「亲测」2020新版个人自动发卡源码 php完整个人发卡网搭建源码...
  14. 数据血缘关系图 工具_MCGS组态软件实现数据报表
  15. spss分析qpcr数据_SPSS统计分析案例:Kappa一致性系数
  16. python中怎么统计英文字符的个数_python 输入一行字符,分别统计出其中英文字母,空格,数字和其他字符的个数用python代码输入一行字符...
  17. Latex 制作表格
  18. win10网络计算机显示不全,win10系统局域网显示计算机设备不完全的解决方法
  19. 【信息系统项目管理师】第三章 立项管理思维导图
  20. html5密码确认属性,HTML5表单及其验证【html自带属性验证】

热门文章

  1. 来啊battle啊,Java和Python你站哪个?
  2. 软考高级系统架构设计师你想知道的全在这
  3. Python123 练习1
  4. 用python打开文件然后写个欢迎代码
  5. 如何让虚拟机mac支持独显_Mac上虚拟机的性能如何提升
  6. C语言单元作业的答案,C语言习题全集+答案.doc
  7. 基于handsome主题的一些美化修改
  8. python notify wait_Python中的threading
  9. 小米手机销量超过苹果晋升全球第二
  10. winedit使用教程_latex及winedit入门指导教程.pdf