来了解一下TS中的infer吧
在 TypeScript 中,infer
类型是一个非常强大且有用的特性。
infer
通常用于条件类型中,它允许我们在类型操作中进行类型推断。简单来说,就是能够从已有的类型中提取出一部分类型信息。
基本用法
infer
关键字只能在条件类型中使用,通常与泛型
和 extends
关键字一起使用。它的语法如下:
typescript
type Case<T> = T extends infer U ? U : never;
这段代码定义了一个类型别名
Case<T>
,它尝试推断泛型参数T
的实际类型。如果T
可以被推断为某个具体的类型U
,那么Case<T>
的类型就是U
;如果T
不能被推断为任何类型(比如T
是一个具体值而不是类型),那么Case<T>
的类型就是never
。
注意
:这个类型变量(infer U)只能在true的分支中使用。
懵逼了千万别怕,看了下面两个例子就秒懂了~
举个例子
案例一:
结合上述代码
type Case = T extends infer U ? U : never;
如果你使用Case<number>
,那么T
会被推断为number
,所以Case<number>
的类型就是number
。
解释
T extends infer U ? U : never
是一个条件类型表达式。条件类型允许你基于一个类型检查的结果来选择两种类型之一。infer U
是类型推断的关键字。它用于在条件类型中声明一个待推断的类型变量U
。这里的infer
关键字告诉TypeScript尝试推断T
的实际类型,并将其赋值给U
。 查的结果来选择返回的类型。如果T
可以被推断为某个类型U
,则返回U
;否则,返回never
类型。
现在,让我们具体看看Case<number>
的情况:
- 当你使用
Case<number>
时,T
被指定为number
。 - 条件类型
T extends infer U
检查number
是否可以被推断为某个类型U
。在这个情况下,number
本身就是一个类型,所以它可以被推断。 - 由于
number
可以被推断,因此U
被推断为number
。
所以可以看到实际上T extends infer U
中,U
的类型是依靠T的类型
获取的
因此如果你使用
Case<42>
,由于42
是一个具体的值而不是类型,所以Case<42>
的类型就是never
。
案例二:
问题 :给定类型别名type
,要求获取HD
类型中属性的类型?
ini
type HD = { name: string, age: number }
type valueType = AttrType<HD>
也就是其中
name
,age
的类型:string ,number
利用infer X
定义变量
r
type AttrType<T> = T extends { name: infer M, age: infer M } ? M : T;
这里infer M
会尝试推断泛型参数T
的实际类型来推断M
变量的类型
- 条件类型
T extends { name: infer M, age: infer M } ? M : T;
检查T
是否可以被赋值给一个对象,该对象有两个属性name
和age
,它们都推断为同一个类型M
。 - 如果
T
满足这个条件(即T
是一个对象,且name
和age
属性的类型相同),那么AttrType<T>
将被推断为该共同的类型M
。 - 如果
T
不满足这个条件(即T
不是一个对象,或者name
和age
属性的类型不相同),那么AttrType<T>
将返回T
本身。
小结
再用白话小结一下:
-
infer X
就相当于声明了一个变量,这个变量X
随后可以使用,甚至和我们常见的for循环
中的let i
很像,只是一个具体值未知形式的表示而已。 -
而这里
X
值的具体值又需要结合extend T
,通过T的类型
获取。