以下是关于 TypeScript 中 infer
关键字的详细解析,涵盖其核心原理、应用场景和实际示例:
一、infer
的基本原理
infer
是 TypeScript 条件类型(Conditional Types)中的关键字,用于在类型匹配时动态推断并捕获类型信息。它必须与 extends
结合使用,语法如下:
type MyType<T> = T extends SomePattern<infer U> ? U : NeverType;
• 核心逻辑:若 T
匹配 SomePattern
的结构,则 infer U
会提取 U
的类型,否则返回备选类型(如 never
或 any
)。
• 特点:
• 仅能在条件类型中使用,无法单独声明类型变量;
• 推断的类型变量仅在 ?
后的分支中有效,无法脱离作用域。
二、常见应用场景
1. 提取函数类型信息
• 返回值类型:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type FnReturn = ReturnType<() => number>; // number
• 参数类型:
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
type FnParams = Parameters<(x: number, y: string) => void>; // [number, string]
2. 处理数组与元组
• 元素类型提取:
type ElementType<T> = T extends (infer U)[] ? U : never;
type NumElement = ElementType<number[]>; // number
• 元组操作:
type FirstElement<T> = T extends [infer F, ...any[]] ? F : never;
type First = FirstElement<[number, string]>; // number
3. 解构 Promise 和对象
• Promise 结果类型:
type UnpackPromise<T> = T extends Promise<infer R> ? R : never;
type PromiseResult = UnpackPromise<Promise<string>>; // string
• 对象属性类型:
type PropType<T, K extends keyof T> = T extends { [P in K]: infer V } ? V : never;
type Age = PropType<{ age: number }, "age">; // number
4. 字符串模板类型操作
• 提取前缀/后缀:
type Prefix<T> = T extends `${infer P}_${string}` ? P : never;
type Pre = Prefix<"hello_world">; // "hello"
三、高级用法
1. 递归处理嵌套结构
• 展平嵌套数组:
type Flatten<T> = T extends Array<infer U> ? Flatten<U> : T;
type FlatArr = Flatten<number[][][]>; // number
2. 联合类型筛选
• 提取特定类型成员:
type ExtractStrings<T> = T extends infer U ? (U extends string ? U : never) : never;
type StrOnly = ExtractStrings<string | number>; // string
3. 深度类型解构
• 多层对象属性提取:
type DeepProp<T> = T extends { a: infer A; b: { c: infer C } } ? [A, C] : never;
type Result = DeepProp<{ a: string; b: { c: number } }>; // [string, number]
四、注意事项与限制
- 作用域限制:
infer
仅在条件类型的分支中有效,无法全局使用。 - 模式匹配限制:无法处理不符合结构或模糊的类型(如非元组数组)。
- 复杂度控制:过度嵌套可能导致类型推导难以维护。
五、总结
infer
是 TypeScript 类型系统的核心工具之一,通过动态类型推断大幅提升了类型操作的灵活性。其典型应用包括:
• 函数类型解构(参数、返回值);
• 容器类型提取(数组、Promise);
• 字符串模板处理;
• 递归与联合类型操作。
结合具体场景合理使用 infer
,可以显著增强代码的类型安全性和可维护性。更多高级用法可参考 TypeScript 官方文档或类型工具库(如 utility-types
)。
在 TypeScript 中,infer
是一个强大的关键字,用于在条件类型(Conditional Types)中推断类型信息。它允许我们在类型系统中进行模式匹配,并从复杂的类型结构中提取特定的类型部分,从而实现更灵活和可复用的类型定义。(CSDN博客)
🔍 基本语法
infer
通常与条件类型一起使用,其基本语法如下:(CSDN博客)
type ExtractType<T> = T extends SomeType<infer U> ? U : DefaultType;
在这个结构中:
T
是待推断的类型。SomeType<infer U>
是用于匹配T
的类型模式。U
是通过infer
关键字推断出的类型变量。- 如果
T
能匹配SomeType<infer U>
的模式,则返回U
;否则返回DefaultType
。(杰克超, CSDN博客)
🛠️ 常见应用场景
1. 提取函数参数类型
type ParamType<T> = T extends (arg: infer P) => any ? P : never;
type ExampleFunc = (x: number) => void;
type Param = ParamType<ExampleFunc>; // Param 的类型为 number
2. 提取函数返回值类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type ExampleFunc = () => string;
type Result = ReturnType<ExampleFunc>; // Result 的类型为 string
3. 提取数组元素类型
type ElementType<T> = T extends Array<infer E> ? E : never;
type ExampleArray = number[];
type Element = ElementType<ExampleArray>; // Element 的类型为 number
4. 提取 Promise 的解析类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type ExamplePromise = Promise<string>;
type Result = UnwrapPromise<ExamplePromise>; // Result 的类型为 string
5. 提取元组的第一个元素类型
type FirstElement<T extends any[]> = T extends [infer First, ...any[]] ? First : never;
type ExampleTuple = [string, number, boolean];
type First = FirstElement<ExampleTuple>; // First 的类型为 string
📚 深入理解
infer
的强大之处在于它能够在类型系统中进行模式匹配和类型推断,从而实现更复杂的类型操作。例如,可以使用 infer
将联合类型转换为交叉类型,或者从复杂的嵌套类型中提取特定的类型信息。(CSDN博客)
此外,TypeScript 内置了一些使用 infer
的类型工具,如 ReturnType<T>
、Parameters<T>
、ConstructorParameters<T>
和 InstanceType<T>
等,这些工具类型在日常开发中非常实用。(杰克超)
📖 参考资料
如果您对某个具体的使用场景或示例感兴趣,欢迎继续提问!