如何在TypeScript中提取数组接口合并为联合类型并实现动态类型函数
让TypeScript对象数组合并函数返回动态推导类型的实现方案
问题分析
你的unit函数当前无法正确推导返回值类型,原因在于泛型T extends object会将数组元素推断为输入对象的联合类型,而返回值默认被推断为空对象{},无法体现对象合并后的属性结构。
解决方案
我们需要让TypeScript保留数组中每个对象的具体类型,并将这些类型合并为交叉类型(模拟对象展开后的属性集合)。以下是两种实现方式:
方式1:递归合并元组类型
通过递归遍历元组中的每个对象类型,逐步合并为交叉类型:
// 递归合并元组中的所有对象类型 type MergeObjects<T extends object[]> = T extends [infer First, ...infer Rest] ? First extends object ? Rest extends object[] ? First & MergeObjects<Rest> : First : MergeObjects<Rest> : {}; function unit<T extends object[]>(arr: [...T]): MergeObjects<T> { let obj = {} as MergeObjects<T>; arr.forEach(val => { obj = { ...obj, ...val }; }); return obj; } // 测试示例 const a = { name: "l" }; const b = { age: 1 }; const c = { gender: "male" }; const person = unit([a, b, c]); // 自动推断类型为:{ name: string; } & { age: number; } & { gender: string; } // TypeScript会自动简化为:{ name: string; age: number; gender: string; }
方式2:联合类型转交叉类型(更简洁)
利用TypeScript的条件类型特性,将元组元素的联合类型转换为交叉类型:
// 将联合类型转换为交叉类型的工具类型 type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; function unit<T extends object[]>(arr: [...T]): UnionToIntersection<T[number]> { let obj = {} as UnionToIntersection<T[number]>; arr.forEach(val => { obj = { ...obj, ...val }; }); return obj; } // 测试示例 const a = { name: "l" }; const b = { age: 1 }; const person = unit([a, b]); // 推断类型为:{ name: string; } & { age: number; },等价于合并后的对象类型
关键细节说明
- 使用
[...T]作为参数类型:确保TypeScript将输入数组推断为元组类型,而非宽泛的object[],这样才能保留每个元素的具体类型信息。 - 交叉类型的作用:交叉类型
A & B会将两个对象的属性合并,若存在重复属性,后面的类型会覆盖前面的,这和JavaScript中对象展开{...a, ...b}的行为完全一致。
内容的提问来源于stack exchange,提问作者why do i have so much question
相关产品推荐
相关产品推荐

