如何实现GetTypeArg类型?提取泛型类型的第N个类型参数
实现
GetTypeArg 类型的方案 要实现能从类型 T 中获取第 N 个泛型参数的 GetTypeArg<T, N>,需要处理两种场景:
- 当
T是未传入泛型参数的泛型类型构造器(比如X),提取其第N个泛型参数的默认值; - 当
T是传入了泛型参数的具体类型(比如Y<unknown>),提取其第N个泛型参数的实际值(包括默认值)。
方案一:针对特定泛型类型的精确实现
这种方案通过条件类型的 infer 关键字匹配目标泛型类型的实例,同时处理泛型构造器的默认参数提取:
// 辅助类型:将1-based数字转换为0-based索引 type MinusOne<N extends number> = N extends 1 ? 0 : N extends 2 ? 1 : N extends 3 ? 2 : N extends 4 ? 3 : N extends 5 ? 4 : // 可根据需求扩展更多数字范围 never; type GetTypeArg<T, N extends number> = // 匹配X的泛型实例,提取对应位置参数 T extends X<infer A> ? (N extends 1 ? A : never) : // 匹配Y的泛型实例,提取对应位置参数 T extends Y<infer A, infer B> ? (N extends 1 ? A : N extends 2 ? B : never) : // 处理泛型构造器,提取默认参数 (<...Args>() => T<...Args>) extends <...Args>(...args: never[]) => any ? Args[MinusOne<N>] : never; // 测试用例 type X<T = string> = {value: T} type Y<T,M=number> = {value1: T, value2: M} type TestX = GetTypeArg<X, 1> // string,符合预期 type TestY1 = GetTypeArg<Y<unknown>, 1> // unknown,符合预期 type TestY2 = GetTypeArg<Y<string[]>, 2> // number,符合预期
方案二:基于属性顺序的通用实现
如果需要不依赖具体泛型类型的通用实现,可以利用对象属性定义顺序来推断泛型参数(TS 2.1+ 会保留字面量对象的属性顺序):
// 辅助类型:将1-based数字转换为0-based索引 type MinusOne<N extends number> = N extends 1 ? 0 : N extends 2 ? 1 : N extends 3 ? 2 : N extends 4 ? 3 : N extends 5 ? 4 : never; // 辅助类型:获取对象按定义顺序的第N个属性类型 type GetNthPropertyType<T, N extends number> = T extends Record<string, any> ? keyof T extends infer Keys ? Keys extends string ? Array<Keys> extends infer KeyArray ? KeyArray[MinusOne<N>] extends infer Key ? T[Key] : never : never : never : never; type GetTypeArg<T, N extends number> = // 先从具体类型的属性中推断泛型参数 GetNthPropertyType<T, N> extends infer PropType ? PropType extends never ? // 再处理泛型构造器的默认参数 (<...Args>() => T<...Args>) extends <...Args>(...args: never[]) => any ? Args[MinusOne<N>] : never : PropType : never; // 测试用例 type X<T = string> = {value: T} type Y<T,M=number> = {value1: T, value2: M} type TestX = GetTypeArg<X, 1> // string,符合预期 type TestY1 = GetTypeArg<Y<unknown>, 1> // unknown,符合预期 type TestY2 = GetTypeArg<Y<string[]>, 2> // number,符合预期
注意事项
- 方案一适合已知泛型类型结构的场景,匹配精确但扩展性有限;
- 方案二更通用,但依赖 TypeScript 对对象属性顺序的保留;
MinusOne类型目前支持1-5的数字,可根据需求扩展更多分支。
内容的提问来源于stack exchange,提问作者kennarddh
相关产品推荐
相关产品推荐

