ts 中 infer 的使用

前言

条件类型的基本语法是: 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 重新起名 叫做 UU不是泛型,只是充当一个 占位符
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 [infer first, ...infer rest] ? [ReverseArr, first] : []

// type rev = ReverseArr
// type rev = [[[[[], 4], 3], 2], 1]

你可能感兴趣的:(Typescript,typescript,前端,javascript)