Angular 19 Signals: `update()` vs `.push()` – Why Immutability Matters
Angular 19 Signals: update() vs .push() – Why Immutability Matters In Angular 19, Signals provide a new way to manage reactive state in a declarative and performant way. But working with arrays in Signals requires understanding a crucial concept: immutability. If you've written something like this: this.characters().push(newCharacter); You might be doing more harm than good. Let’s explore why this is problematic and what the correct approach is using update(). The Problem with .push() this.characters().push(newCharacter); This code directly mutates the array returned by the signal. While it appears to work, Angular won’t detect the change, because: The reference to the array hasn't changed. Signals track changes by reference, not by internal mutation. As a result, your UI will not update. The Correct Way: update() this.characters.update((prev) => [...prev, newCharacter]); This is the reactive and immutable way to update a signal. A new array is returned using the spread operator. Angular detects the new reference and triggers reactivity. Any component bound to the signal will automatically reflect the update. Why Immutability Matters Signals work best when updates are referentially transparent: They don’t track internal mutations. They react to set() and update() calls where the reference changes. Mutating state in place (like with .push()) breaks reactivity. Comparison Table Method Reactive? Immutable? Recommended? this.characters.update(fn) ✅ Yes ✅ Yes ✅ ✅ ✅ this.characters().push(...) ❌ No ❌ No ❌ Never Example Use Cases Add a character: this.characters.update((prev) => [...prev, newCharacter]); Remove a character: this.characters.update((prev) => prev.filter(c => c.id !== target.id)); Replace entire list: this.characters.set([...newList]); Final Thoughts The beauty of Angular Signals is in their predictability and reactivity. But this only works when we respect their design principles. If you're managing collections in Signals, always use immutable operations through update() or set(). Leave mutation behind—and enjoy fully reactive UIs. Happy signaling! ⚡

Angular 19 Signals: update()
vs .push()
– Why Immutability Matters
In Angular 19, Signals provide a new way to manage reactive state in a declarative and performant way. But working with arrays in Signals requires understanding a crucial concept: immutability.
If you've written something like this:
this.characters().push(newCharacter);
You might be doing more harm than good. Let’s explore why this is problematic and what the correct approach is using update()
.
The Problem with .push()
this.characters().push(newCharacter);
This code directly mutates the array returned by the signal. While it appears to work, Angular won’t detect the change, because:
- The reference to the array hasn't changed.
- Signals track changes by reference, not by internal mutation.
- As a result, your UI will not update.
The Correct Way: update()
this.characters.update((prev) => [...prev, newCharacter]);
This is the reactive and immutable way to update a signal.
- A new array is returned using the spread operator.
- Angular detects the new reference and triggers reactivity.
- Any component bound to the signal will automatically reflect the update.
Why Immutability Matters
Signals work best when updates are referentially transparent:
- They don’t track internal mutations.
- They react to
set()
andupdate()
calls where the reference changes. - Mutating state in place (like with
.push()
) breaks reactivity.
Comparison Table
Method | Reactive? | Immutable? | Recommended? |
---|---|---|---|
this.characters.update(fn) |
✅ Yes | ✅ Yes | ✅ ✅ ✅ |
this.characters().push(...) |
❌ No | ❌ No | ❌ Never |
Example Use Cases
Add a character:
this.characters.update((prev) => [...prev, newCharacter]);
Remove a character:
this.characters.update((prev) => prev.filter(c => c.id !== target.id));
Replace entire list:
this.characters.set([...newList]);
Final Thoughts
The beauty of Angular Signals is in their predictability and reactivity. But this only works when we respect their design principles.
If you're managing collections in Signals, always use immutable operations through update()
or set()
. Leave mutation behind—and enjoy fully reactive UIs.
Happy signaling! ⚡