infer
infer 是在 typescript 2.8
中新增的关键字。
infer
能够在 extends
条件类型的字句中,在实在分支中援用此推断类型变量,推断待推断的类型。
例如:用infer
推断函数的返回值类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;type fn = () => numbertype fnReturnType = ReturnType<fn> // number
在这个例子中,
T extends U ? X : Y
的模式为条件类型。
infer R
代表待推断的返回值类型,如果 T
是一个函数(...args: any[]) => infer R
,则返回函数的返回值 R
,否则返回any
案例:加深了解
反解 Promise
// promise 响应类型type PromiseResType<T> = T extends Promise<infer R> ? 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<typeof strPromise> // Promise<string>// 反解type StrPromiseRes = PromiseResType<StrPromise> // strtype PersonPromise = ReturnType<typeof personPromise> // Promise<Person>// 反解type PersonPromiseRes = PromiseResType<PersonPromise> // Person
反解函数入参类型
type Fn<A extends any[]> = (...args: A) => anytype FnArgs<T> = T extends Fn<infer A> ? A : anyfunction strFn (name: string) {}type StrFn = FnArgs<typeof strFn> // [string]
tuple 转 union ,如:[string, number] -> string | number
type ElementOf<T> = T extends Array<infer E> ? E : nevertype TTuple = [string, number];type ToUnion = ElementOf<ATuple>; // string | number
new 操作符
// 获取参数类型type ConstructorParameters<T extends new (...args: any[]) => any> = T extends new (...args: infer P) => any ? P : never;// 获取实例类型type InstanceType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer R ? R : any;class TestClass { constructor( public name: string, public string: number ) {}}type Params = ConstructorParameters<typeof TestClass>; // [string, numbder]type Instance = InstanceType<typeof TestClass>; // TestClass
react - reducer
// 定义function useReducer<R extends Reducer<any, any>, I>( reducer: R, // ReducerState 推断类型 initializerArg: I & ReducerState<R>, initializer: (arg: I & ReducerState<R>) => ReducerState<R>): [ReducerState<R>, Dispatch<ReducerAction<R>>];// infer推断type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never;// Reducer类型type Reducer<S, A> = (prevState: S, action: A) => S;// 应用 reducerconst 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<T = any> { [isRefSymbol]: true value: T}export function ref<T>(value: T): T extends Ref ? T : Ref<UnwrapRef<T>>export type UnwrapRef<T> = { cRef: T extends ComputedRef<infer V> ? UnwrapRef<V> : T ref: T extends Ref<infer V> ? UnwrapRef<V> : T array: T object: { [K in keyof T]: UnwrapRef<T[K]> }}[T extends ComputedRef<any> ? 'cRef' : T extends Array<any> ? '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) // Ref<number>const count = ref(ref(2)) // Ref<number>
参考
- 了解TypeScript中的infer关键字
- Vue3 跟着尤雨溪学 TypeScript 之 Ref 类型从零实现
- 巧用 TypeScript(五)---- infer