如何用TypeScript实现支持多参数的对象合并函数?
TypeScript 实现支持任意数量参数的对象合并函数
问题背景
我已经写好了一个只能合并两个对象的函数,类型推断正常,鼠标悬停返回值能看到所有合并后的属性:
const mergeObjects = <T, U>(a: T, b: U): T & U => { const mergedObject = {} _.merge(mergedObject, a, b) return mergedObject as T & U } const a = { a: '1', b: '2', } const b = { c: '3', d: '4', } const c = mergeObjects(a, b)
现在想把这个函数改成能接收任意多个对象参数,但自己试的代码有问题——不仅逻辑上硬编码了参数,类型也没法正确推断返回值:
const mergeObjects = <T extends object>(...sources: T[]) => { const mergedObject = {} _.merge(mergedObject, a, b) // 这里写死了a和b,没用到传入的所有参数 return mergedObject // 没有正确的返回类型标注 } const a = { a: '1', b: '2', } const b = { c: '3', d: '4', } const d = { e: '5', f: '6', } const c = mergeObjects(a, b, d) // 没法看到合并后的完整属性类型
补充:用的是Lodash的_.merge,目的是封装它,返回新对象不修改原对象。
解决方法
要同时搞定任意参数支持和正确的类型推断,得从类型定义和函数逻辑两方面改:
1. 类型层面:把所有参数类型合并成交叉类型
用泛型元组来接收参数,再通过类型转换把参数的联合类型转成交叉类型,这样返回值就能正确包含所有对象的属性。
2. 逻辑层面:动态传入所有参数
把_.merge的参数改成扩展所有传入的sources,确保每个对象都被合并到新创建的空对象里。
最终可行代码:
// 辅助类型:把联合类型转成交叉类型 type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; const mergeObjects = <T extends object[]>(...sources: T): UnionToIntersection<T[number]> => { const mergedObject = {}; // 把所有传入的对象都传给_.merge _.merge(mergedObject, ...sources); return mergedObject as UnionToIntersection<T[number]>; } // 测试用例 const a = { a: '1', b: '2' }; const b = { c: '3', d: '4' }; const d = { e: '5', f: '6' }; const c = mergeObjects(a, b, d); // 现在鼠标悬停c,能看到它包含a、b、c、d、e、f所有属性
关键点说明
<T extends object[]>:限定传入的参数必须是对象组成的数组T[number]:取出数组里所有元素的类型,形成一个联合类型UnionToIntersection<T[number]>:把联合类型转换成交叉类型,也就是最终合并后的对象类型_.merge(mergedObject, ...sources):动态传入所有参数,保证所有对象都被合并到新对象中
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

