update a specific index of an array when using spread operator

Can we allow dynamic index of arrays to be update/add via a spread operator just like we do for objects, e.g here a reducer example:

const state = { myObj: {items: ["a", "b", "c"]} };
const index = 2;
const newValue = "d";

return {
   ...state,
   myObj: {
       ...state.myObj,
      items: [
        ...state.myObj.items,
        [index]: newValue, // do something like this
      ]
   }
} // => { myObj: {items: ["a", "b", "d"]} };

This has been requested at least 3 times on Stackoverflow, so its seems like natural pattern people want to use.

[1] References

Thanks

no, because array destructuring syntax is actually iterator destructuring syntax, and iterators don't have indexes.

You could use with.

const state = { myObj: {items: ["a", "b", "c"]} };
const index = 2;
const newValue = "d";

return {
   ...state,
   myObj: {
       ...state.myObj,
      items: state.myObj.items.with(index, newValue)
   }
}
4 Likes

They're talking about creation, not destructuring. Destructuring could literally just be done via const {[index]: value} = someArray for const value = someArray[index], and I've lately even started doing const {1: value} = result for extracting groups in RegExp.prototype.exec results (typically for ones I know will match).

To this goal, you could spec [...prev, [key]: value, a, ...next] to align more with how object properties are evaluated in the face of object spread:

// Loosely what'd happen under the hood
let $result = []
// ...prev
for (let $i of prev) $result.push($i)
// [index]: value
$result[key] = value
// a
$result.push(a)
// ...next
for (let $i of next) $result.push($i)
return $result

You can use Object.assign

const state = { myObj: {items: ["a", "b", "c"]} };
const index = 2;
const newValue = "d";
return {
   ...state,
   myObj: {
       ...state.myObj,
      items: Object.assign([...state.myObj.items], { [index]: newValue })
   }
}

but in your usecase, probably just use something like lodash.merge/mergeWith

1 Like

Yes that is correct! @ claudiameadows and caub, thank you.

I still prefer the above way where you select the index and update it but this could be another option:

const index = 1;
const state = { myObj: { items: ["a", "b", "c"] } };

const nextState = {
  ...state,
  myObj: {
    ...state.myObj,
    items: [...state.myObj.items, ...{ [index]: newValue }],
  },
};

Or maybe this:

...

items: [...state.myObj.items, ...([][index] = newValue)]

I believe it would make updating values in a array mutch easier for people going forward, as a todo app, you always update some list, and split(...) is quite confusing for an update for begginers, and this index selector would make life easier, not only for beginners but also experts.

Both of those are already valid syntax whose semantics cannot be changed.