You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript实现addOrUpdate函数遇阻:对象数组增改需求求助

问题描述

我正在尝试实现一个addOrUpdate函数,但多次尝试都失败了。我有一个对象数组,每个对象包含valueGroup键和values字符串数组(类型定义为SelectedValues)。需求逻辑如下:首先检查对应valueGroup的对象是否存在,不存在则新增;若存在,检查目标value是否在其values数组中,存在则删除,不存在则添加。我最初尝试用函数式方法(map)实现,但出现了嵌套数组的问题,希望完全用函数式方式解决。目前现有代码无法更新对象,总是新增包含新值的对象,而且代码过于复杂。我使用的是TypeScript,以下是我的代码:

type SelectedValues = {
    valueGroup: string;
    values: string[];
};

function updateSelectedValues(selectedValues: SelectedValues[], valueGroup: string, value: string): SelectedValues[] {
    // If array empty add first object
    if (selectedValues.length === 0) {
        return [{ valueGroup: valueGroup, values: [value] }];
    } else {
        // look if valueGroup is already there
        const index = selectedValues.findIndex((find) => find.valueGroup === valueGroup);
        if (index === -1) {
            // if no add new valueGroup with first values
            return [...selectedValues, { valueGroup: valueGroup, values: [value] }];
        } else {
            // if valueGroup is there, look if value is already in values
            const findedValues = selectedValues[index];
            if (findedValues.values.includes(value)) {
                // yes, remove value from values
                return [...selectedValues, { ...findedValues, values: findedValues.values.filter((filter) => filter !== value) }];
            } else {
                // no, add value to values
                return [
                    ...selectedValues.filter((object) => object.valueGroup === valueGroup),
                    { ...findedValues, values: [...findedValues.valueGroup, value] },
                ];
            }
        }
    }
}

我通过按钮点击事件传入valueGroup和value,期望数组按以下示例变化:

// 初始状态:数组为空,逐步插入两个分组并填充值
const initialState: SelectedValues[] = [
    {
        valueGroup: "valueGroupOne",
        values: ["some", "more", "example"]
    }, 
    {
        valueGroup: "valueGroupTwo",
        values: ["ddd", "sss", "aaa"]
    }
];

// 新增一个分组后的状态
const afterAddGroup: SelectedValues[] = [
    {
        valueGroup: "valueGroupOne",
        values: ["some", "more", "example"]
    }, 
    {
        valueGroup: "valueGroupTwo",
        values: ["ddd", "sss", "aaa"]
    },
    {
        valueGroup: "valueGroupThree",
        values: ["ssss", "dddsd", "adsdas"]
    }
];

// 向已有分组添加新值后的状态
const afterAddValue: SelectedValues[] = [
    {
        valueGroup: "valueGroupOne",
        values: ["some", "more", "example", "newValueadded"]
    }, 
    {
        valueGroup: "valueGroupTwo",
        values: ["ddd", "sss", "aaa"]
    },
    {
        valueGroup: "valueGroupThree",
        values: ["ssss", "dddsd", "adsdas"]
    }
];

// 从已有分组删除值后的状态
const afterRemoveValue: SelectedValues[] = [
    {
        valueGroup: "valueGroupOne",
        values: ["some", "more", "example"]
    }, 
    {
        valueGroup: "valueGroupTwo",
        values: ["ddd", "sss", "aaa"]
    },
    {
        valueGroup: "valueGroupThree",
        values: ["ssss", "dddsd", "adsdas"]
    }
];
现有代码问题分析
  1. 更新逻辑错误:处理已存在valueGroup的删除/添加操作时,错误地将修改后的对象追加到原数组末尾(比如return [...selectedValues, 新对象]),导致原分组对象保留,新增重复对象,而非替换原对象。
  2. 语法错误:添加值的逻辑中,[...findedValues.valueGroup, value]误用了valueGroup(字符串类型),展开后会变成字符数组,正确应该是[...findedValues.values, value]。
  3. 分支冗余:单独处理空数组的分支,增加了代码复杂度;使用findIndex加索引访问的方式,不如函数式遍历简洁。
函数式解决方案

以下是纯函数式的实现,通过map遍历数组处理更新,统一逻辑分支,避免修改原数据:

type SelectedValues = {
    valueGroup: string;
    values: string[];
};

function updateSelectedValues(
    selectedValues: SelectedValues[],
    targetGroup: string,
    targetValue: string
): SelectedValues[] {
    let groupExists = false;

    // 遍历数组,处理匹配的分组
    const updatedArray = selectedValues.map(item => {
        if (item.valueGroup !== targetGroup) {
            return item;
        }
        groupExists = true;
        // 处理values:存在则删除,不存在则添加
        const updatedValues = item.values.includes(targetValue)
            ? item.values.filter(v => v !== targetValue)
            : [...item.values, targetValue];
        return { ...item, values: updatedValues };
    });

    // 未找到目标分组时,新增分组
    return groupExists ? updatedArray : [...updatedArray, { valueGroup: targetGroup, values: [targetValue] }];
}

实现说明

  • 纯函数特性:所有操作均返回新的数组和对象,不修改原数据,符合函数式编程要求。
  • 逻辑统一:无需单独处理空数组,空数组时map返回空数组,自动进入新增分支。
  • 高效遍历:仅遍历数组一次完成更新判断与处理,性能更优。
  • 错误修正:修复了原代码中valueGroup误用的问题,确保values数组操作正确。
测试示例

对应你期望的场景,调用示例如下:

// 初始状态
let state: SelectedValues[] = [];

// 新增第一个分组
state = updateSelectedValues(state, "valueGroupOne", "some");
state = updateSelectedValues(state, "valueGroupOne", "more");
state = updateSelectedValues(state, "valueGroupOne", "example");

// 新增第二个分组
state = updateSelectedValues(state, "valueGroupTwo", "ddd");
state = updateSelectedValues(state, "valueGroupTwo", "sss");
state = updateSelectedValues(state, "valueGroupTwo", "aaa");

// 新增第三个分组
state = updateSelectedValues(state, "valueGroupThree", "ssss");
state = updateSelectedValues(state, "valueGroupThree", "dddsd");
state = updateSelectedValues(state, "valueGroupThree", "adsdas");

// 向第一个分组添加新值
state = updateSelectedValues(state, "valueGroupOne", "newValueadded");

// 从第一个分组删除值
state = updateSelectedValues(state, "valueGroupOne", "newValueadded");

内容的提问来源于stack exchange,提问作者maxfromgermany

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 21:36:31