如何将多个泛型TypeScript列表合并为联合类型的新列表?
实现类型安全的泛型List合并方法
需求说明
我需要给现有的泛型List<T>类添加一个静态merge方法,实现以下功能:
- 接收任意数量的
List实例作为参数 - 将所有输入列表的项合并到一个新的
List实例中 - 返回的新列表类型必须是输入列表项类型的联合类型,完全避免
any类型,保证类型安全
比如合并List<string>和List<number>后,返回的实例应该是List<string | number>类型。
现有List类代码
class List<T> { private items: T[]; constructor() { this.items = []; } push(item: T): void { this.items.push(item); } getItems(): T[] { return this.items; } }
当前问题
最初的merge方法用any类型定义,无法正确推断返回的联合类型:
class List<T> { // ...现有代码... static merge(...lists: List<any>[]): List<any> { // TODO: 实现逻辑 } }
我尝试过的实现也没能解决类型推断问题,返回的是List<any>:
static merge<T extends any[]>(...lists: { getItems: () => any }[]): List<T[number]> { const mergedList = new List<T[number]>(); lists.forEach(list => { list.getItems().forEach(item => mergedList.push(item)); }); return mergedList; }
解决方案
要实现类型安全的合并,我们需要通过泛型元组捕获输入类型,再用辅助类型提取每个列表的项类型,最终组成联合类型。
完整实现代码
// 辅助类型:从List实例中提取其项的类型 type ExtractItemType<L> = L extends List<infer U> ? U : never; class List<T> { private items: T[]; constructor() { this.items = []; } push(item: T): void { this.items.push(item); } getItems(): T[] { return this.items; } // 类型安全的merge静态方法 static merge<T extends List<any>[]>(...lists: T): List<ExtractItemType<T[number]>> { // 创建新的合并列表,类型为提取出的联合类型 const mergedList = new List<ExtractItemType<T[number]>>(); // 遍历所有输入列表,合并项 lists.forEach(list => { list.getItems().forEach(item => mergedList.push(item)); }); return mergedList; } }
验证示例
const stringList = new List<string>(); stringList.push("hello"); const numberList = new List<number>(); numberList.push(123); // mergedList的类型会被正确推断为List<string | number> const mergedList = List.merge(stringList, numberList); // 可以正常添加string或number类型的项 mergedList.push("world"); mergedList.push(456); // 尝试添加其他类型会触发TypeScript报错(比如boolean) // mergedList.push(true); // 类型“boolean”的参数不能赋给类型“string | number”的参数
原理说明
- 泛型元组
T:T extends List<any>[]让TypeScript捕获所有输入List实例的类型组成的元组(比如输入List<string>和List<number>时,T就是[List<string>, List<number>])。 T[number]:将元组类型转换为联合类型,即List<string> | List<number>。ExtractItemType:通过条件类型的infer关键字,从每个List类型中提取其内部的项类型,最终得到string | number。
这样就能保证返回的List实例类型完全基于输入列表的类型,实现类型安全的合并。
内容的提问来源于stack exchange,提问作者Dino56m
相关产品推荐
相关产品推荐

