如何从泛型对象数组推导对应类型的元组?
如何实现提取泛型对象数组中类型的元组类型?
需求描述
给定泛型参数T extends Array<SomeObjectWithGenericParameter<unknown>>,需要推导出一个元组类型,其中每个元素对应原数组中SomeObjectWithGenericParameter内部的泛型类型。
基础示例
type SomeObjectWithGenericParameter<T> = { value: T; } // 待实现的类型 type ExtractDataAsArray<T extends Array<SomeObjectWithGenericParameter<unknown>>> = unknown; type TypedArray = [a: string, b: number]; // 期望A等价于TypedArray type A = ExtractDataAsArray<[{value: string}, {value: number}]>;
实际场景示例
type LoadingPayload<T> = { data:T, isSuccess: true, isLoading: false, } | { data: null, isSuccess: false, isLoading: true, } // 待实现的类型 type ExtractDataTypes<T extends Array<LoadingPayload<unknown>>> = unknown; function myFunction<T extends Array<LoadingPayload<unknown>>> (dataPayloads: T, processData: (data: ExtractDataTypes<T>) => void) {} const d1 : LoadingPayload<string> = { isLoading: true, isSuccess: false, data: null, }; const d2 : LoadingPayload<number> = { isLoading: false, isSuccess: true, data: 2, } myFunction([d1,d2], (data) => { const a: string = data[0]; // 期望data[0]为string类型 const b: number = data[1]; // 期望data[1]为number类型 const c: never = data[2]; // 期望data[2]为never类型 });
尝试的错误实现
以下实现未达到预期效果,示例中data被推断为Array<number>而非元组[string, number]:
type ExtractDataTypes<T extends Array<LoadingPayload<unknown>>> = { [K in keyof T ] : T[K] extends LoadingPayload<infer U> ? U : never; }
解决方案
问题出在泛型约束的类型上:使用Array<LoadingPayload<unknown>>作为约束时,TypeScript会将数组字面量宽泛地推断为数组类型(比如LoadingPayload<string | number>[]),而非保留元素具体类型的元组类型。我们需要调整约束,让TypeScript优先推断元组结构,再通过映射类型提取内部泛型。
正确实现代码
type LoadingPayload<T> = { data:T, isSuccess: true, isLoading: false, } | { data: null, isSuccess: false, isLoading: true, } // 修改约束为readonly LoadingPayload<unknown>[],保留元组结构 type ExtractDataTypes<T extends readonly LoadingPayload<unknown>[]> = { [K in keyof T]: T[K] extends LoadingPayload<infer U> ? U : never; } // 同步修改函数的泛型约束 function myFunction<T extends readonly LoadingPayload<unknown>[]>(dataPayloads: T, processData: (data: ExtractDataTypes<T>) => void) {} const d1 : LoadingPayload<string> = { isLoading: true, isSuccess: false, data: null, }; const d2 : LoadingPayload<number> = { isLoading: false, isSuccess: true, data: 2, } myFunction([d1,d2], (data) => { const a: string = data[0]; // 正确推断为string const b: number = data[1]; // 正确推断为number const c: never = data[2]; // 正确推断为never });
原理说明
- 将泛型约束从
Array<LoadingPayload<unknown>>改为readonly LoadingPayload<unknown>[],TypeScript会将传入的数组字面量推断为元组类型(比如[LoadingPayload<string>, LoadingPayload<number>]),而非合并类型的数组。 - 映射类型
{ [K in keyof T]: ... }作用于元组时,会逐个处理每个索引对应的元素类型,最终生成对应的元组结果,而非数组类型。
内容的提问来源于stack exchange,提问作者dwjohnston
相关产品推荐
相关产品推荐

