TypeScript 使用 infer 实现类型推断
首先从一个问题引入,下面有一个模拟发送请求的方法,返回内容被包裹在 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))])
}
很多同学上来就用 typeof
和 ReturnType
一把梭哈:
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 实现类型推断相关推荐
- TypeScript Type Innference(类型推断)
在这一节,我们将介绍TypeScript中的类型推断.我们将会讨论类型推断需要在何处用到以及如何推断. 基础 在TypeScript中,在几个没有明确指定类型注释的地方将会使用类型推断来提供类型信息. ...
- Typescript 类型推断
TypeScript 能根据一些简单的规则推断(检查)变量的类型,你可以通过实践,很快的了解它们. #定义变量 变量的类型,由定义推断: `let foo = 123; // foo 是 'numbe ...
- 使用TypeScript映射和条件类型使React组件更出色
by Deepu K Sasidharan 通过Deepu K Sasidharan 使用TypeScript映射和条件类型使React组件更出色 (Make your React component ...
- java全局变量和局部变量_Java 10 –局部变量类型推断
java全局变量和局部变量 在本文中,我们将看到作为JEP 286的一部分提出的名为Local Variable Type Inference的Java10功能. 从Java的第一个版本开始,它是一种 ...
- java 鲜为人知的知识点_鲜为人知的Java 8功能:广义目标类型推断
java 鲜为人知的知识点 遍历Java 8的功能列表 , 广义目标类型推断使我震惊,因为它是一个特别有趣,鲜为人知的瑰宝. 看起来Java语言设计人员将减轻过去使用泛型(Java 5-7)时遇到的某 ...
- Java 10 –局部变量类型推断
在本文中,我们将看到作为JEP 286的一部分提出的名为Local Variable Type Inference的Java10功能. 从Java的第一个版本开始,它是一种强类型语言,在这里我们需要提 ...
- 鲜为人知的Java 8功能:广义目标类型推断
遍历Java 8功能列表 , 广义目标类型推断使我震惊,因为它是一个特别有趣,鲜为人知的瑰宝. 看起来Java语言设计人员将减轻过去使用泛型(Java 5-7)时遇到的某些痛苦. 让我们看看他们的例子 ...
- 第七节:在 TypeScript 中什么是类型推论?
上一节,我们学习了TypeScript中的一种新的数据类型:元组Tuple.没学习上一节的同学可以戳:<又一种新的数据类型:元组Tuple> 这一节,我们一起来学习一下TypeScript ...
- matlab中float类型的_Java局部变量类型推断(Var类型)的26条细则
原文链接:https://dzone.com/articles/var-work-in-progress 作者:Anghel Leonard 译者:沈歌 Java局部变量类型推断(LVTI),简称 v ...
- Java 10:局部变量类型推断
Java 10:局部变量类型推断 在本文中,我们将深入研究Java 10中引入的局部变量类型推断的新特性.我们将讨论使用局部变量类型推断的范围和局限性. 此功能是作为JEP(JDK增强提案)的一部分提 ...
最新文章
- C++中的STL算法详解
- Dagger2从入门到熟练
- 如何用 ajax 连接mysql数据库,并且获取从中返回的数据。ajax获取从mysql返回的数据。responseXML分别输出不同数据的方法。...
- leetcode 506. 相对名次(Java版)
- html表单实验总结,HTML表单总结
- Ngs File Type Transfer
- linux 驱动线程与进程,Linux内核学习之二-进程与线程
- 004 Leaflet 第四个demo 使用自己的图标替换marker图标
- win10 修改进入 cmd 命令行的默认路径
- 一、Java语言基础(5)_数组高级——方法参数的值传递机制
- try-catch(C# 参考)
- QCustomplot绘图性能的改善
- php自动发卡程序8.0_「亲测」2020新版个人自动发卡源码 php完整个人发卡网搭建源码...
- 数据血缘关系图 工具_MCGS组态软件实现数据报表
- spss分析qpcr数据_SPSS统计分析案例:Kappa一致性系数
- python中怎么统计英文字符的个数_python 输入一行字符,分别统计出其中英文字母,空格,数字和其他字符的个数用python代码输入一行字符...
- Latex 制作表格
- win10网络计算机显示不全,win10系统局域网显示计算机设备不完全的解决方法
- 【信息系统项目管理师】第三章 立项管理思维导图
- html5密码确认属性,HTML5表单及其验证【html自带属性验证】