前言
条件类型的基本语法是: T extends U ? X : Y
- infer 只能在条件类型的
extends
子句中使用 - infer 得到的类型只能在
true 语句
中使用,即 X 中
一、基本使用
例:定义一个类型,如果是数组类型,那就返回数组元素的类型,否则传入什么类型就返回什么类型
1、不使用 infer
T[number]
:T 是数组,number 在这里是数组的索引
,T[number] 就是数组里的每个元素
type TYPE<T> = T extends Array<any> ? T[number] : T
// 验证使用
type t1 = TYPE<string>
// type t1 = string
type t2 = TYPE<number[]>
// type t2 = number
type t3 = TYPE<(string | number)[]>
// type t3 = string | number
// 会把元祖变为联合类型
type t31 = TYPE<[string, number]>
// type t31 = string | number
2、使用 infer 实现相同效果
- infer 可以理解为
把 any 重新起名
叫做U
,U不是泛型
,只是充当一个占位符
type TYPE2<T> = T extends Array<infer U> ? U : T
// 验证
type t4 = TYPE2<(string | number)[]>
// type t4 = string | number
type t5 = TYPE<string>
// type t5 = string
// 会把元祖变为联合类型
type t6 = TYPE2<[string, number]>
// type t6 = string | number
二、类型提取
1、用 infer 定义数组参数的每一项
type Every<T extends any[]> = T extends [infer one, infer two, infer three] ? three : []
type some = Every<[1, 2, 'a']>
// type some = "a"
2、 提取数组的首项
type First<T extends any[]> = T extends [infer one, ...any[]] ? one : []
type first = First<['a', 'b', 'c']>
// type first = "a"
infer
只定义了首项,...any[]
将剩余参数解构true语句
中返回第一项
3、 提取数组最后一项
type Last <T extends any[]> = T extends [...any[], infer last] ? last : []
type last = Last<['a', 'b', 'ccc']>
// type last = "ccc"
infer
只定义了最后一项,...any[]
将前面所有参数解构true语句
中返回最后一项rest
剩余参数在函数参数
使用时,只能定义在最后
,与这里的使用有所区别
三、类型过滤
与类型提取的思路一样,只是 true语句
中的 返回
不同
1、pop 的实现
- pop 是剔除最后一项,把
前面所有项
和最后一项
分开定义即可 最后一项
我们是不需要的,所以不关注它是什么类型
,直接定义为unknown
type Pop <T extends any[]> = T extends [...infer rest, unknown] ? rest : []
type pop = Pop<[1, 2, 3, 4]>
// type pop = [1, 2, 3]
2、shift 的实现
- 与 pop 思路一致
- shift 是 剔除第一项,把
第一项
和后面所有项
分开定义即可 第一项
是不关注的,所以定义为unknown
type Shift <T extends any[]> = T extends [unknown, ...infer rest] ? rest : []
type shift = Shift<[1, 2, 3, 4]>
// type shift = [2, 3, 4]
四、递归
例:用 infer 实现数组的翻转
- 把
第一项
和其他项
分开定义,true语句中
把第一项放在最后一位
,然后对其他项进行同样的递归
递归逻辑必须解构
,否则会使数组层级加深从而得到错误的答案(每一次递归返回的都是数组)
type ReverseArr <T extends any[]> = T extends [infer first, ...infer rest] ? [...ReverseArr<rest>, first] : []
type arr = [number, string, boolean, symbol]
type rev = ReverseArr<arr>
// type rev = [symbol, boolean, string, number]
// 错误写法:
// type ReverseArr <T extends any[]> = T extends [infer first, ...infer rest] ? [ReverseArr<rest>, first] : []
// type rev = ReverseArr<arr>
// type rev = [[[[[], 4], 3], 2], 1]