Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to Iterate through heterogenous object in Typescript

I have a state object and an update object that will be combined with the state object, though null in the update means delete so I can’t just do {...a, ...b} with them.

const obj = {
    other: new Date(),
    num:5,
    str:"original string"
}

const objUpdate:Partial<typeof obj> = {
    num:6,
    str:"updated string"
}

The task: Iterate through the update object and apply its values to the original object. This is how I ideally would do it:

Object.entries(objUpdate).forEach(([k,v])=>{
    if (v === undefined) return;
    if (v === null){
        delete obj[k]; // <-
        return;
    }
    obj[k] = v; // <-
})

But at the indicated lines I get an error that No index signature with a parameter of type 'string' was found on type '{ other: Date; num: number; str: string; }'. Ideally Typescript would know that k is already keyof typeof objUpdate (edit: here’s possibly why) but I guess I can explicitly indicate that:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Object.entries(objUpdate).forEach(([k,v])=>{
    if (v === undefined) return;
    if (v === null){
        delete obj[k as keyof typeof objUpdate];
        return;
    }
    obj[k as keyof typeof objUpdate] = v; // <-
})

At the indicated line it complains that Type 'string | number | Date' is not assignable to type 'never'. Type 'string' is not assignable to type 'never'.

  1. Is there a way to help Typescript infer typings correctly in this situation?
  2. Is there a better approach to what I am trying to accomplish?

>Solution :

Dynamically deleting keys on an object is both slow in JavaScript and can make typing more difficult in TypeScript. The easiest way to approach this by a good margin would be to tweak the other parts of your code that reference the state so that they check if the value is null or not. So, instead of having a state object of

const obj = {
    other: <someDate>,
    str: <someString>
}

there would be

const obj = {
    other: <someDate>,
    num: null,
    str: <someString>
}

Using this approach, typing will just work, and the state update will be as trivial as {...a, ...b}.

To type the initial state, map the keys to a new object type with null added in.

const obj = {
    other: new Date(),
    num:5,
    str:"original string"
}
type Obj = typeof obj;
type ObjState = {
  [K in keyof Obj]: Obj[K] | null;
};

// ...

const [stateObj, setStateObj] = useState<ObjState>(obj);
// Update:
setStateObj({ ...stateObj, ...objUpdate });

If some part of the code requires the object to be formatted with the null properties removed (such as for a database query), do that by creating a new object when it’s necessary, just before sending the object, rather than changing the state’s shape.

const objWithNullPropertiesRemoved: Partial<Obj> = Object.fromEntries(
  Object.entries(stateObj)
    .filter(([, val]) => val !== null)
);
// send the objWithNullPropertiesRemoved somewhere
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading