在 TypeScript 中条件类型的用法是:

T extends U ? X : Y

跟 JS 中的条件表达式一样,如果 extends 语句为真,则取X类型 ,反之得到Y类型 。我们这里把X称为条件类型的真分支,Y 称为假分支。

现在,在 TypeScript 2.8 之后,我们可以在 extends 条件语句中使用 infer 关键字引入一个变量表示推断的类型,这个变量可以被用在真分支中,也就是说 infer 实际上是一个声明关键字,我们可以用它来声明一个变量,而该变量表示的是 infer 所处位置的类型。

以标准库的 ReturnType 为例:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;const getFullName = (firstName: string, lastName: string): string {return `${firstName}_${lastName}`;
}
const fullName: ReturnType<typeof getFullName> = getFullName('foo', 'bar');

这里 ReturnType<T> 接收一个任意函数,在 extends 分支把推断的函数返回值的类型赋给变量 R,从而得到该类型。这里需要注意的是,我们只能在 extends 条件语句中使用 infer 关键字,不能在诸如类型参数这样的地方使用它:

type ReturnType<T extends (...args: any[]) => infer R> = R;  // Error.

既然可以获取到函数的返回值的类型,同样也可以推断出函数的参数类型,标准库的Paramaters<T>把函数的每个参数类型提取到一个元组中:

type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;const getFullName = (firstName: string, lastName: string, age: number): string =>{return `${firstName}_${lastName}`;
}
type params = Parameters<typeof getFullName> // [string, string, number]

除了把函数参数列表的类型提取出来,进一步深入,假如函数的参数是单个对象,我们可以利用 infer 把参数的结构推断出来:

type FunctionWithMappedArgument<P extends { [key: string]: any }> = (args: P) => any;
type DestructuredArguments<F extends FunctionWithMappedArgument<any>> = F extends FunctionWithMappedArgument<infer R> ? R : never;declare function drawPoint(config: { x: number, y: number, color: string}): any;
const args: DestructuredArguments<typeof drawPoint> = {x: 4,y: 6,
}

这里我们先定义出参数类型为单个对象的通用函数 FunctionWithMappedArgument<T>,接着定义解构参数的方法 DestructuredArguments<T>,这个方法做的事情是接收一个FunctionWithMappedArgument<T> 类型的函数,然后把函数的泛型参数T推断为新的变量 R,这样编译器就会替我们计算出 R 的解构。

通过上面的代码,我们就可以把函数的参数类型提取出来,无需再声明一个类型,编码过程中编辑器的智能感知也能很好地进行代码补全提示。

多处 infer 推断一个变量

上面展示的例子都只用到了一个 infer,在 extends 条件语句中,我们可以有多个 infer,只不过它们只能作用于同一个变量,根据推断位置的不同产生的类型也有所不同。

在共变的位置,会推断出联合类型:

type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type T10 = Foo<{ a: string, b: string }>;  // string
type T11 = Foo<{ a: string, b: number }>;  // string | number

在逆变的位置,推断的是交叉类型:

type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
type T20 = Bar<{ a: (x: string) => void, b: (x: string) => void }>;  // string
type T21 = Bar<{ a: (x: string) => void, b: (x: number) => void }>;  // string & number

函数重载中的推断

当作用于一个有多处调用签名(函数重载)的类型时,infer 只对最后一个签名生效,不可能基于参数列表的不同进行重载。

declare function foo(x: string): number;
declare function foo(x: number): string;
declare function foo(x: string | number): string | number;
type T30 = ReturnType<typeof foo>;  // string | number

在条件类型中使用 infer 关键字相关推荐

  1. SAP MM 条件类型中PB00的‘Group Cond.‘标记的作用?

    SAP MM 条件类型中PB00的'Group Cond.'标记的作用? 如果没勾选这个标记,PO中的每个ITEM都根据其数量去取Scale里的价格, 而非PO汇总后的数量去取SCALE里的价格. 测 ...

  2. TypeScript 2.8引入条件类型

    最新发布的TypeScript 2.8包含了若干主要特性和一些问题修复,其中最为重要的是新增了条件类型,开发人员可以根据其他类型的特征为变量选择适当的类型. 条件类型最适合与泛型组合在一起使用.如果一 ...

  3. Typescript中的extends关键字

    前言 extends关键字在TS编程中出现的频率挺高的,而且不同场景下代表的含义不一样,特此总结一下: 表示继承/拓展的含义 表示约束的含义 表示分配的含义 基本使用 extends是 ts 里一个很 ...

  4. TS中的条件类型(ReturnType)

    本偏介绍TS另一种高级类型-条件类型. 官方文档:https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distr ...

  5. java继承类型的用法_详解Java中使用externds关键字继承类的用法

    理解继承是理解面向对象程序设计的关键.在Java中,通过关键字extends继承一个已有的类,被继承的类称为父类(超类,基类),新的类称为子类(派生类).在Java中不允许多继承. (1)继承 cla ...

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

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

  7. 定义定价用途的条件类型(Condition Types)

    一.说明 条件的存取顺序(access sequences)可以设置若干个条件表(Condition Table),但仅有存取顺序还不能维护条件的记录.能够维护条件记录的是条件类型(Condition ...

  8. python 关键字大全_一日一技:用实例列举python中所有的关键字(01)

    Python关键字列表 本教程提供有关Python中使用的所有关键字的简要信息. 关键字是Python中的保留字.我们不能将关键字用作变量名,函数名或任何其他标识符. 以下是Python中所有关键字的 ...

  9. [转载] java中50个关键字以及各自用法大全

    参考链接: Java中的默认数组值 关键字和保留字的区别 正确识别java语言的关键字(keyword)和保留字(reserved word)是十分重要的.Java的关键字对java的编译器有特殊的意 ...

最新文章

  1. 百度搜索查询命令——组合型
  2. ACE - Reactor模式源码剖析及具体实现(大量源码慎入)
  3. enum python_enum:python实现枚举也很优雅
  4. 【深度学习】图像去噪:一种基于流的图像去噪神经网络
  5. mysql索引红黑联盟_MySQL索引
  6. [机器学习]回归--Polinomial Regression 多项式回归
  7. ASP.NET Core 防止跨站请求伪造(XSRF\/CSRF)攻击
  8. vsc写vue生成基本代码快捷键_基于vue2.X的webpack基本配置,教你手动撸一个webpack4的配置...
  9. Atitit layout art 布局的艺术目录1. SpringLayout 类 弹簧布局管理器 12. BoxLayout( html默认布局) 11.SpringLayout
  10. Greenplum 实时数据仓库实践(5)——实时数据同步
  11. 如何在宝贝描述里加旺旺图标和免费电话
  12. 计算机模拟做报童模型,用基于计算机随机模拟的下降法求解报童问题
  13. 短信验证码和语音验证码的对比
  14. 计算机组成原理最难的是,计算机组成原理最后冲刺重难点梳理_跨考网
  15. 曾经最好用的浏览器凉了?正在被大批网站抛弃
  16. 码代码时遇到的小插曲
  17. 嵌入式系统设计电子书
  18. 操作系统基础(十)物理地址和虚拟地址
  19. 忙里偷闲又把自己的JWT实现改进了一下
  20. 创意黑板教育教学PPT模板

热门文章

  1. 来看看优酷是如何测试 App 响应式布局的!
  2. 开源要安全!Linux 基金会、GitHub、GitLab、Google 联合起来了!
  3. 推荐系统如何一键实现工业级部署? ElasticCTR 百度开讲
  4. 涂鸦智能传感合作伙伴大会圆满落幕,打造安防传感新生态
  5. 倪光南:中国 5G 有望成为世界第一
  6. 这个充电宝用起来好方便!
  7. 2019 世界读书日,让程序员疯狂的 13 本豆瓣高分技术书!
  8. 10193 条票房数据告诉你《流浪地球》领跑的电影档战果如何?
  9. VS Code Java 开发指南!
  10. 成功送小米上市的米粉们,反被 P2P 爆雷炸成了灰!