本文深入解析 TypeScript 2.8 新增的 infer 关键字,阐述其在 extends 条件类型中推断未知类型变量的机制。通过函数返回值、Promise 解包、元组转联合类型、构造函数参数及 React/Vue 源码示例,展示 infer 在复杂类型场景下的实际应用与技巧。
整理记录一下 infer 关键字的使用,以防日后遗忘。该概念初看较为晦涩,需要仔细梳理。
infer
infer 关键字于 TypeScript 2.8 版本中引入。
在 extends 条件类型的字句中,infer 允许在真实分支(true branch)中引用被推断的类型变量,从而实现对未知类型的推导。
以下示例展示如何利用 infer 推断函数的返回值类型。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type fn = () => number
type 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> // str
type PersonPromise = ReturnType<typeof personPromise> // Promise<Person>
// 反解
type PersonPromiseRes = PromiseResType<PersonPromise> // Person
反解函数入参类型。
type Fn<A extends any[]> = (...args: A) => any
type FnArgs<T> = T extends Fn<infer A> ? A : any
function strFn (name: string) {
}
type StrFn = FnArgs<typeof strFn> // [string]
将元组转换为联合类型,例如将 [string, number] 转换为 string | number。
type ElementOf<T> = T extends Array<infer E> ? E : never
type 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;
// 使用 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<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
到此这篇关于深入理解typescript中的infer关键字的使用的文章就介绍到这了,更多相关typescript infer关键字内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!