如何用TypeScript的Array.reduce实现对象数组按ID去重并累加数量
报错原因
- reduce泛型参数错误:你声明的reduce返回值类型是
MiniBagItem单个对象,但实际初始值是数组、返回值也是数组,类型不匹配直接触发类型报错。 - Map未指定泛型:TS会默认推断Map的键值为
unknown类型,读取obj.sku作为键、获取对应值的时候都会报类型不匹配。 - 重复插入逻辑:你在三元判断里已经给不存在的条目执行了
acc.push(obj),后面又多写了一次acc.push(obj),会导致所有条目重复插入结果数组。 - 索引逻辑错误:你存到Map里的是原数组的下标,但是结果数组
acc的长度和原数组不一样,用原数组下标取acc[seen]根本拿不到正确的对象。
正确实现
基础版(易读)
直接在reduce的累加数组中查找同sku的条目,累加数量即可:
export interface MiniBagItem { name?: string; sku?: string; quantity?: number; } const item1: MiniBagItem = { name: "test", sku: "123", quantity: 1 }; const item2: MiniBagItem = { name: "test", sku: "123", quantity: 1 }; const item3: MiniBagItem = { name: "testNew", sku: "456", quantity: 1 }; const miniBagItems: MiniBagItem[] = [item1, item2, item3]; const mergedItems = miniBagItems.reduce<MiniBagItem[]>((acc, current) => { // 过滤sku为空的异常数据 if (!current.sku) return acc; // 查找是否已经有同sku的条目 const existed = acc.find(item => item.sku === current.sku); if (existed) { // 累加数量,加空值兼容避免TS报错 existed.quantity = (existed.quantity ?? 0) + (current.quantity ?? 0); } else { // 新增条目,解构避免修改原对象 acc.push({...current}); } return acc; }, []);
高性能版(大数组适用)
结合Map减少每次遍历查找的开销,时间复杂度O(n):
const mergedItems = Array.from( miniBagItems.reduce<Map<string, MiniBagItem>>((map, current) => { if (!current.sku) return map; if (map.has(current.sku)) { const existed = map.get(current.sku)!; existed.quantity = (existed.quantity ?? 0) + (current.quantity ?? 0); } else { map.set(current.sku, {...current}); } return map; }, new Map()) ).map(([, item]) => item);
如果需要按itemId归并,只需要把代码中所有的sku替换为itemId即可,逻辑完全一致。
内容的提问来源于stack exchange,提问作者Pradeep S
相关产品推荐
相关产品推荐

