Update object's nested values dynamically

Viewed 174

I need to implement a function that updates nested values of an object with dynamic keys. The first key is a top level property of that object, the second key is a key of the nested object behind that property.

interface IFoo {
    categoryOne: {
        a: string,
        b: string,
        c: string,
    };
    categoryTwo: {
        x: string,
        y: string,
        z: string,
    }
}

const obj: IFoo = {
    categoryOne: {
        a: 'a_string',
        b: 'b_string',
        c: 'c_string',
    },
    categoryTwo: {
        x: 'x_string',
        y: 'y_string',
        z: 'z_string',
    }
}

function changeObj(category: string, key: string, value: string, obj: IFoo): void {
    obj[category][key] = value;
}

changeObj('categoryOne', 'b', 'B_STRING', obj);

I want to do that without type casting as much as possible. So I've tried narrowing the types of category and key down to acceptable union types. I was able to get the result:

const categoryOneKeys = categoryMap.categoryOne;
const categoryTwoKeys = categoryMap.categoryTwo;
type CategoryOneKeys = typeof categoryOneKeys[number];
type CategoryTwoKeys = typeof categoryTwoKeys[number];

const isKeyInCategoryOne = (key: string): key is CategoryOneKeys => {
    return categoryOneKeys.some(category => key === category);
}

const isKeyInCategoryTwo = (key: string): key is CategoryTwoKeys => {
    return categoryTwoKeys.some(category => key === category);
}

function changeObj(category: string, key: string, value: string, obj: IFoo): void {
    switch(category) {
        case 'categoryOne':
            if (!isKeyInCategoryOne(key)) return;
            obj[category][key] = value;
            break;
        case 'categoryTwo':
            if (!isKeyInCategoryTwo(key)) return;
            obj[category][key] = value;
            break;
    }
}

changeObj('categoryOne', 'b', 'B_STRING', obj);

but there's a lot of repetition and maintainability of this code is poor. One would have to make a lot of changes just to add another category to the inteface. What would be the optimal way of doing this?

UPD The changeObj function is an input handler. It receives arguments from HTML form iniputs, thus its signature can't be changed. I.e. category and key must be of type string.

Playground

0 Answers
Related