From 4da109685de21cec4dac6db4f7c3d68daa9554fe Mon Sep 17 00:00:00 2001 From: root Date: Fri, 21 Aug 2026 00:43:08 +0200 Subject: [PATCH] fix(signals): avoid reading unrelated state slices in patchState --- modules/signals/spec/state-source.spec.ts | 14 ++++++++++++++ modules/signals/src/state-source.ts | 14 +++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/modules/signals/spec/state-source.spec.ts b/modules/signals/spec/state-source.spec.ts index 7de0b29a34..c50045a2d8 100644 --- a/modules/signals/spec/state-source.spec.ts +++ b/modules/signals/spec/state-source.spec.ts @@ -3,6 +3,7 @@ import { effect, EnvironmentInjector, Injectable, + linkedSignal, signal, } from '@angular/core'; import { TestBed } from '@angular/core/testing'; @@ -61,6 +62,19 @@ describe('StateSource', () => { }); describe('patchState', () => { + it('does not read unrelated state slices for partial state objects', () => { + const name = signal(''); + const inaccessible = linkedSignal(() => { + throw new Error('Failed to read state slice'); + }); + const stateSource = { + [STATE_SOURCE]: { name, inaccessible }, + }; + + expect(() => patchState(stateSource, { name: 'John' })).not.toThrow(); + expect(name()).toBe('John'); + }); + [ { name: 'with signalState', diff --git a/modules/signals/src/state-source.ts b/modules/signals/src/state-source.ts index fdff85abd8..a512885c5a 100644 --- a/modules/signals/src/state-source.ts +++ b/modules/signals/src/state-source.ts @@ -82,13 +82,18 @@ export function patchState( Partial> | PartialStateUpdater> > ): void { - const currentState = untracked(() => getState(stateSource)); + const requiresCurrentState = updaters.some( + (updater) => typeof updater === 'function' + ); + const currentState = requiresCurrentState + ? untracked(() => getState(stateSource)) + : undefined; const newState = updaters.reduce( (nextState: State, updater) => ({ ...nextState, ...(typeof updater === 'function' ? updater(nextState) : updater), }), - currentState + currentState ?? ({} as State) ); const signals = stateSource[STATE_SOURCE]; @@ -97,7 +102,10 @@ export function patchState( for (const key of Reflect.ownKeys(newState)) { if (stateKeys.includes(key)) { const signalKey = key as keyof State; - if (currentState[signalKey] !== newState[signalKey]) { + const currentValue = currentState + ? currentState[signalKey] + : untracked(() => signals[signalKey]()); + if (currentValue !== newState[signalKey]) { signals[signalKey].set(newState[signalKey]); } } else if (typeof ngDevMode !== 'undefined' && ngDevMode) {