infer

// infer 作用是推断泛型参数,必须配合着extends使用,需要跟着变量名
interface User {
  name: string
  age: number
}
// 写一个传入具体泛型的type,然后可以推断其泛型的type
// 定义一个具用泛型的type
type promiseType = Promise<User>
// 1.泛型接收的是一个Promise有泛型的type,它是extends于Promise的,此处要相互对应,如果Set<number>,就要改为extends Set
// 2.使用infer U来指代Prmoise的泛型,如果能提出来就返回U,不然直接返回传入的值
type getPromiseT<T> = T extends Promise<infer U> ? U : T

type T = getPromiseT<promiseType> // T=User
// type T = getPromiseT<Promise<User>> // T=User

// 此处嵌套是一样的,extends同步嵌套即可
// type promiseType = Promise<Promise<Promise<User>>>
// type getPromiseT<T> = T extends Promise<Promise<Promise<infer U>>> ? U : T

// infer协变:协变是发生在对象中的,推断出来是联合类型,结果是对象中的所有属性类型的联合集合
const obj = {
  name: '11',
  age: 22
}
type Bar<T> = T extends {name: infer U, age: infer U} ? U : T
type B = Bar<typeof obj> // string | number

// infer逆变: 是发生在函数身上的,推断出来的是交叉类型,结果是返回参数的类型交叉集合
type FnBar<T> = T extends {a:(x:infer U)=>void, b:(y:infer U)=> void} ? U : T
type F = FnBar<{a:(x:number)=>void,b:(y:string)=>void}>
// string & number 不合理 所以是 nerve
type N = FnBar<{a:(x:string)=>void,b:(y:string)=>void}>
// string

// 获取元组类型的某个值的类型
type Arr = ['a','b','c']
// 此处可以返回two或three, 就是取不同位置的类型了
type I1<T extends Array<any>> = T extends [infer one,infer two,infer three] ? one : []
type A1 = I1<Arr> // 'a' 
// 如果只是需要取第一个,则用...
type I2<T extends Array<any>> = T extends [infer one,...any[]] ? one : []
type A2 = I2<Arr> // 'a' 
// 模拟实现数组pop,删除最后一个类型,同理可以推断出如何左删除第一个
type I3<T extends Array<any>> = T extends [...infer Res,unknown] ? Res : []
type A3 = I3<Arr> // ['a','b']

// infer递归
// 需求是要元组类型翻转从[1,2,3],成为[3,2,1]
// 1.思路第一步应该是把第一个放到最后
type Arr2 = [1,2,3]
type I4<T extends Array<any>> = T extends [infer first,...infer Res] ? [...Res, first] : T
type A4 = I4<Arr2> // 此时是[2,3,1]

// 使用递归可一步到位,递归I5,会把[2,3]再执行一次I5调换位置
type I5<T extends Array<any>> = T extends [infer first,...infer Res] ? [...I5<Res>, first] : T
type A5 = I5<Arr2> // 此时是[3,2,1]

 

posted on 2025-02-19 01:45  ChoZ  阅读(21)  评论(0)    收藏  举报

导航