TypeScript 中的 infer 关键字

简介: TypeScript 中的 infer 关键字

TypeScript 笔记TypeScript 中的 infer


1. infer 关键字解析

1.1 使用条件类型提取类型

使用 条件类型 来应用约束然后 提取 出类型,是一种非常常见的操作。比如:

type Flatten<T> = T extends any[] ? T[number] : T;

这里我们定义了一个类型工具 Flatten<T>,你可以理解为一个接受类型作为参数并返回一个类型的函数,其中尖括号中的T(<T>)就是那个类型函数的参数。

后面相当于类型函数的部分是一个 条件类型表达式,形式看起来有点像 JavaScript 中的条件表达式,事实上你也可以借助其进行理解。其语法格式为:

SomeType extends OtherType ? TrueType : FalseType;

与 JavaScript 条件表达式以 逻辑真假 为判断依据类似,

在 Typescript 条件类型表达式 中,以 左侧的类型可分配给右侧的类型 为依据。

  • 当左侧的类型 可分配 给右侧的类型时,第一个分支(称作 true 分支)中获得该类型;
  • 反之,你将在后一个分支(称作 false 分支)中获得类型;

在上面的代码 (T extends any[] ? T[number] : T) 中,如果传如的类型 T 可以分配给类型 any[](比如T是一个string[]) ,则返回类型 T[number],否则返回 T 本身。

比如,我们调用该类型工具生成一个新的类型 MyType

type MyType = Flatten1<['a',2]>;  // 2 | "a"

由于类型 ['a',2] 可以分配给 any[](或者说是 any[] 的子类型,两者就像继承关系,所以用extends 关键字) 提取出了其中的类型作为一个新的类型 MyType

1.2 使用 infer 关键字表达提取

Typescript 为我们提供了一种 使用 infer 关键字 从我们在 条件类型的 true 分支中 比较的类型进行推断的方法。

换句话说, infer 关键字用于声明一个动态生成的 类型变量,这个类型变量是用于临时存放被捕获的类型。例如:

type Flatten<T> = T extends Array<infer I> ? I : T;

这个例子中,要求传入的类型 T 可分配给 Array<infer I>,我们知道泛型 Array<U> 中的 U 表示约束该数组的成员类型都为 U,但是 <infer I> 却不会再约束 数组的所有成员都为同一个类型 I。这里的区别在于:

在下面这个表达式中:

T extends Array<U> ? I : T;

T 必须是所有成员类型一致的情况下才能分配给 Array<U>

比如数组 [1,2,3] 可分配给 number[],进一步还可分配给 Array<U> 这都是兼容的。但是 [1,'a','b']由于其中成员类型不一样,它不能分配给 Array<U>

然而在下面这个表达式中:

T extends Array<infer I> ? I : T;

infer I动态生成的一个个新类型 ,因此这看起来就像是在使用 any[],说明不论数组中的值是何种类型,只要是一个数组,就满足 T extends Array<infer I>,并且满足的同时 infer I 表示被推断出来的 联合类型

2. 来源于 lib.es5.d.ts 的例子

这部分类型工具声明摘抄于 typescript 内置的类型声明模块lib.es5.d.ts。包括:

  • ThisParameterType
  • OmitThisParameter
  • Parameters
  • ReturnType
  • InstanceType
  • Awaited

他们的声明均使用了 infer 关键字

2.1 提取函数类型的“this”参数的类型

type ThisParameterType<T> = 
T extends (this: infer U, ...args: never) => 
any ? U : unknown;

解释:

  • 如果函数类型没有“this”参数,则为“unknown”。

2.2 从函数类型中移除“this”参数

type OmitThisParameter<T> = 
unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;

2.3 获取元组中函数类型的参数

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

2.4 获取函数类型的返回类型

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

2.5 获取构造函数类型的返回类型

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

2.6 递归展开一个类型的"awaited type"

type Awaited<T> =
    T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode
        T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
            F extends ((value: infer V, ...args: infer _) => any) ? // 如果`then`的参数是可调用的,则提取第一个参数
                Awaited<V> : // recursively unwrap the value
                never : // `then`这个参数是不可调用的
        T; // non-object 或者 non-thenable
  • 递归展开一个类型的"awaited type"。
  • 非 promise 的 “thenables” 应该 resolve never。这模仿了 await 的行为。
目录
相关文章
|
6月前
|
存储 JavaScript 前端开发
TypeScript 5.2 beta 浅析:新的关键字 using 与新版装饰器元数据
TypeScript 5.2 beta 浅析:新的关键字 using 与新版装饰器元数据
109 0
|
5月前
|
JavaScript 存储
25.【TypeScript 教程】infer 关键字
25.【TypeScript 教程】infer 关键字
43 2
|
5月前
|
JavaScript
24.【TypeScript 教程】is 关键字
24.【TypeScript 教程】is 关键字
43 0
|
安全
TypeScript-infer关键字和TypeScript-unknown类型
TypeScript-infer关键字和TypeScript-unknown类型
50 0
学习TypeScript28(infer 递归)
具体思路 首先使用泛型约束 约束只能传入数组类型的东西 然后从数组中提取第一个,放入新数组的末尾,反复此操作,形成递归 满足结束条件返回该类型
46 0
学习TypeScript28(infer 递归)
|
JavaScript 前端开发
TypeScript 笔记 TypeScript 中的 infer
本文介绍 TypeScript 中的 infer 及其使用方式。
117 0
|
JavaScript 前端开发 Java
TypeScript 基础学习之泛型和 extends 关键字
越来越多的团队开始使用 TS 写工程项目, TS 的优缺点也不在此赘述,相信大家都听的很多了。平时对 TS 说了解,仔细思考了解的也不深,借机重新看了 TS 文档,边学习边分享,提升对 TS 的认知的同时,也希望能在平时的工作中能用上,少写一点 any。
116 0
|
JavaScript
【TypeScript教程】# 11:super关键字
【TypeScript教程】# 11:super关键字
94 0
【TypeScript教程】# 11:super关键字
学习TypeScript27(infer 类型提取)
类型参数 T 通过extends 约束 只能是数组类型,然后通过infer 声明局部 First 变量做提取,后面的元素可以是任意类型,然后把局部变量返回
60 0
|
JavaScript
学习TypeScript26(TS进阶用法infer )
定义一个类型 如果是数组类型 就返回 数组元素的类型 否则 就传入什么类型 就返回什么类型
118 0