typescript 中的 infer 关键字的理解

infer
infer 是在 typescript 2.8中新增的关键字。
infer 可以在 extends 条件类型的字句中,在真实分支中引用此推断类型变量,推断待推断的类型。
例如:用infer推断函数的返回值类型

type ReturnType = T extends (...args: any[]) => infer R ? R : any; type fn = () => number type fnReturnType = ReturnType // number

在这个例子中,
T extends U ? X : Y的形式为条件类型。
infer R 代表待推断的返回值类型,如果 T 是一个函数(...args: any[]) => infer R,则返回函数的返回值 R,否则返回any
案例:加深理解
反解 Promise
// promise 响应类型 type PromiseResType = T extends Promise ? R : T// 验证 async function strPromise() { return 'string promise' }interface Person { name: string; age: number; } async function personPromise() { return { name: 'p', age: 12 } as Person }type StrPromise = ReturnType // Promise // 反解 type StrPromiseRes = PromiseResType // strtype PersonPromise = ReturnType // Promise// 反解 type PersonPromiseRes = PromiseResType【typescript 中的 infer 关键字的理解】 // Person

反解函数入参类型
type Fn = (...args: A) => any type FnArgs = T extends Fn ? A : anyfunction strFn (name: string) {}type StrFn = FnArgs // [string]

tuple 转 union ,如:[string, number] -> string | number
type ElementOf = T extends Array ? E : nevertype TTuple = [string, number]; type ToUnion = ElementOf; // string | number

new 操作符
// 获取参数类型 type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never; // 获取实例类型 type InstanceType any> = T extends new (...args: any[]) => infer R ? R : any; class TestClass {constructor( public name: string, public string: number ) {} }type Params = ConstructorParameters; // [string, numbder]type Instance = InstanceType; // TestClass

react - reducer
// 定义 function useReducer( reducer: R, // ReducerState 推断类型 initializerArg: I & ReducerState, initializer: (arg: I & ReducerState) => ReducerState ): [ReducerState, Dispatch>]; // infer推断 type ReducerState = R extends Reducer ? S : never; // Reducer类型 type Reducer = (prevState: S, action: A) => S; // 使用 reducer const reducer = (x: number) => x + 1; const [state, dispatch] = useReducer(reducer, ''); // Argument of type "" is not assignable to parameter of type 'number'.

vue3 - ref
export interface Ref { [isRefSymbol]: true value: T }export function ref(value: T): T extends Ref ? T : Ref>export type UnwrapRef = { cRef: T extends ComputedRef ? UnwrapRef : T ref: T extends Ref ? UnwrapRef : T array: T object: { [K in keyof T]: UnwrapRef } }[T extends ComputedRef ? 'cRef' : T extends Array ? 'array' : T extends Ref | Function | CollectionTypes | BaseTypes ? 'ref' // bail out on types that shouldn't be unwrapped : T extends object ? 'object' : 'ref']// 使用 const count = ref({ foo: ref('1'), bar: ref(2) })// 推断出 const count: Ref<{ foo: string; bar: number; }>const count = ref(2) // Refconst count = ref(ref(2)) // Ref

参考
  • 理解TypeScript中的infer关键字
  • Vue3 跟着尤雨溪学 TypeScript 之 Ref 类型从零实现
  • 巧用 TypeScript(五)---- infer

    推荐阅读