Array.prototype.toSpliced()

Two differences from splice, not one: it copies instead of mutating, AND it returns the resulting array instead of the removed elements. The second catches people more than the first.

Array methodES2023Live demo
Common call
items.toSpliced(i, 1)
Returns
the RESULTING array — not the removed elements
Replaces
a copy followed by splice, plus reading the copy
Watch out
splice returns what was removed; toSpliced returns what is left
array.toSpliced(start[, skipCount[, ...items]])
→ Array

Demo

Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
startnumberstart index
countnumberhow many to skip
Output
[1, 2, 3, 4, 5].toSpliced(1, 2)
[1, 4, 5]

Compare the first case with splice: [1,2,3,4,5].splice(1, 2) returns [2, 3] — the removed elements — while toSpliced returns [1, 4, 5], the array you are left with. Same arguments, opposite return value. That is the difference to internalise, and it is why swapping one for the other is not a drop-in change even once mutation stops mattering.

Parameters

NameTypeRequiredDescription
startnumberyesIndex to begin changing at. Negative counts from the end.
skipCountnumberno (to the end)How many elements to omit from the result. Named skipCount rather than deleteCount, because nothing is deleted — the source is untouched.
...itemsanyno (none)Elements to insert at start in the new array.

Return value

Array — A NEW array with the changes applied — the RESULT, not the removed elements. That return value is the opposite of splice.

Common patterns

Remove an item from state
One call, no copy step, no mutation.
setItems(items.toSpliced(index, 1));
Insert without removing
A skipCount of 0 makes it a pure insert.
const next = items.toSpliced(2, 0, newItem);
The pre-2023 equivalent
Copy, splice the copy, then use the copy — three steps.
const next = [...items];
next.splice(index, 1);

Examples

1. Returns the result
[1, 2, 3, 4].toSpliced(1, 2)
Returns
[1, 4]
2. splice returns removed
[1, 2, 3, 4].splice(1, 2)
Returns
[2, 3]
3. Insert only
[1, 2, 3].toSpliced(1, 0, 9)
Returns
[1, 9, 2, 3]
4. Original untouched
const a = [1, 2, 3]; a.toSpliced(0, 1); a
Returns
[1, 2, 3]
5. Count past the end
[1, 2, 3].toSpliced(1, 99)
Returns
[1]
6. Negative start
[1, 2, 3].toSpliced(-2, 1)
Returns
[1, 3]

Pitfalls

1. The return value is the opposite of splice
splice hands back the elements it removed; toSpliced hands back the array that remains. Converting splice code to toSpliced without noticing gives you the wrong data with no error at all.
Expected the removed
const removed = items.toSpliced(1, 2);
the RESULTING array
Slice for the removed
const removed = items.slice(1, 3);
the removed elements
2. The copy is shallow
Same as the rest of the family. A new outer array, the same inner objects — mutating one through the result changes it in the original.
Shared objects
const a = [{n: 1}, {n: 2}];
const b = a.toSpliced(1, 1);
b[0].n = 9;
a[0].n
9
Deep copy
const b = structuredClone(a).toSpliced(1, 1);
independent
3. ES2023 and newer only
Node 20+, and reasonably recent browsers. Older targets need copy-then-splice, which is three lines and easy to get subtly wrong.
Missing method
items.toSpliced(1, 1)
TypeError: items.toSpliced is not a function
Copy then splice
const next = [...items];
next.splice(1, 1);
same result

When to use

Use it
  • Removing or inserting in state without mutating
  • Any place copy-then-splice appears today
  • Expression contexts where a three-line copy would not fit
Reach for something else
  • You want the REMOVED elements → splice, or slice the range first
  • You own the array and want it changed in place → splice
  • Runtimes older than ES2023 → copy then splice
  • Removing by a test rather than an index → filter

Notes

Complexity
O(n) — the whole array is copied
Return
A new array with the changes applied; the original is never modified
CPython impl
V8: Builtins-array-tospliced.tq
Memory
Allocates a full copy
Thread-safe
Single-threaded; the source is only read

FAQ

Because the two answer different questions. splice mutates, so the array is already updated and the useful thing left to hand back is what it removed. toSpliced does not mutate, so the only useful thing to return is the new array.

items.splice(1, 2);      // [2, 3]  — removed
items.toSpliced(1, 2);   // [1, 4]  — result

History

ES2023
Added by the change-array-by-copy proposal, alongside toSorted, toReversed and with.