Skip to content

@ngrx/signals: Improve Developer Experience for Immutability #4030

@rainerhahnekamp

Description

@rainerhahnekamp

Which @ngrx/* package(s) are relevant/related to the feature request?

store

Information

Ensuring that state updates are immutable is crucial for Signal to emit correctly and trigger necessary DOM updates, derived signals, or side effects. Currently, an immutable runtime check is available, but only in development mode due to its potential performance impact.

To enhance the robustness of applications and facilitate debugging, I propose two additional behaviours:

  • Option to enable the immutable check in production mode: There are many Angular applications where this “safety net” outweighs performance penalties by far. Especially “classic enterprise applications” containing many forms where the business logic runs in the backend.
  • $update with Readonly Types: Compilation checks are highly preferable to runtime checks because they allow potential issues to be discovered before the runtime. The $update method could be enhanced to provide the state as a recursive Readonly type to achieve this. This would extend to arrays as ReadonlyArray, removing mutable methods like push.

Example:

import { signalStore, withMethods, withState } from '@ngrx/signals';
type User = { id: number; name: string };
type UsersState = { users: User[]; loading: boolean };

declare function withImmutabilityCheck(mode: 'disabled' | 'devMode' | 'always');

const UsersStore = signalStore(
  withImmutabilityCheck('always'), // <— immutable check
  withState<UsersState>({ users: [], loading: false }),
  withMethods(({ $update, users }) => {
    return {
      addUser(user: User): void {
        $update((state) => {
          state.users.push(user); // 💥compilation error because ReadonlyArray<User>
          state.loading = true; //  💥compilation error because Readonly<UsersState>

          return state;
        });
      },
    };
  })
);

If accepted, I would be happy to provide an initial PR.

Describe any alternatives/workarounds you're currently using

No response

I would be willing to submit a PR to fix this issue

  • Yes
  • No

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions