Array.prototype.with()
Returns a copy of the array with the element at one index replaced by a new value.
with(index, value)- Added in JavaScript ECMAScript 2023
Parameters
| Parameter | Type | Description |
|---|---|---|
$index | number | Zero-based index to change, converted to an integer. Negative values count back from the end. |
$value | any | The value assigned at that index in the returned array. |
Return value
ArrayA new array with the element at index replaced by value; the original array is unchanged.
Errors
Throws a RangeError if index >= array.length or index < -array.length.
with() is the copying replacement for arr[i] = v. It builds a new array of the same length, copies every element across, and substitutes value at the requested index. The original is never touched, which is exactly what state containers and frozen data need.
When to reach for it
Use it wherever you must not mutate: React or Redux state, props passed downward, values captured in a closure, or arrays you have frozen deliberately. It also reads well in a chain, since it returns an array you can keep operating on.
What trips people up
- It throws instead of growing the array. Unlike
arr[10] = von a 3-element array,arr.with(10, v)raises aRangeError. Use toSpliced() to insert or extend. - The copy is shallow — untouched elements are the same object references, so mutating one still affects the original.
- Sparse arrays become dense: every hole in the source turns into an explicit
undefined. - It always allocates. Replacing many indexes one at a time in a loop is O(n²); collect the changes and build the array once instead.
with() is a reserved-looking word but a perfectly ordinary method name — only the standalone with statement is restricted.
Example
When to use it
- Update one item in an immutable list held in application state.
- Replace the last element of a chain result with arr.with(-1, value).
- Patch a row of a frozen configuration array without mutating the source.
- Produce a modified copy to compare against the original by reference.
Frequently asked questions
How do I replace an item in an array without mutating it?
Use arr.with(index, value), which returns a new array with just that index changed. It is the copying counterpart of arr[index] = value and accepts negative indexes.
Why does with() throw a RangeError?
Because the index is outside the existing bounds — index >= length or index < -length. with() never grows the array; use toSpliced() to insert new elements or push() on a mutable copy.
Is with() a deep copy?
No, it makes a shallow copy: every element other than the replaced one is the same reference as in the source. Spread or structuredClone the individual objects if you need them independent.
More examples
Immutable state update
The frozen source array is unchanged and the new array is a different reference, but element 0 is still the same object — the copy is shallow, which is what identity-based change detection expects.
const todos = Object.freeze([
{ id: 1, done: false },
{ id: 2, done: false },
]);
const i = todos.findIndex((t) => t.id === 2);
const next = todos.with(i, { ...todos[i], done: true });
console.log(next.map((t) => t.done));
console.log(todos.map((t) => t.done));
console.log(next === todos, next[0] === todos[0]);Chaining copying methods
Each copying method hands a fresh array to the next, so the pipeline never mutates raw. The last line shows the hole at index 1 materialising as undefined in the result.
const raw = [5, 1, 4, 2];
console.log(raw.toSorted((a, b) => a - b).with(0, 0).toReversed());
console.log(raw);
// Sparse holes become explicit undefined
console.log([1, , 3].with(0, 9));Replacing several indexes efficiently
Both produce the same array, but the reduce version allocates a full copy per patched index. For more than a couple of changes, a single map() is the cheaper shape.
const base = ["a", "b", "c", "d"];
const patch = new Map([[1, "B"], [3, "D"]]);
// Each with() copies the whole array
console.log([...patch].reduce((acc, [i, v]) => acc.with(i, v), base));
// One pass instead of one copy per change
console.log(base.map((v, i) => (patch.has(i) ? patch.get(i) : v)));
Discussion