ngrx/platform

Patch methods do not correctly resolve generic collection names withEntities

Opened this issue · 4 comments

Which @ngrx/* package(s) are the source of the bug?

signals

Minimal reproduction of the bug/regression with instructions

A TypeScript error occurs when attempting to use the patchState function with addEntity on a store with withEntities. The error indicates a type mismatch between PartialStateUpdater<NamedEntityState<E, Collection>> and the expected parameter type.

import {
  patchState,
  signalStoreFeature,
  type,
  withMethods,
} from '@ngrx/signals';
import { addEntity, EntityId, withEntities } from '@ngrx/signals/entities';

function withFeature<E extends { id: EntityId }, Collection extends string>(
  collection: Collection
  // collection: string,  //this removes the errors
) {
  const config = {
    collection: collection,
    entity: type<E>(),
  };
  return signalStoreFeature(
    withEntities(config),
    withMethods((store) => ({
      add: (entity: E) =>
        patchState(
          store,
          addEntity(entity, { collection })
        ),
    }))
  );
}
X [ERROR] TS2345: Argument of type 'PartialStateUpdater<NamedEntityState<E, Collection>>' is not assignable to parameter of type 'Partial<{ [
K in keyof { [K in keyof NamedEntityState<E, Collection>]: NamedEntityState<E, Collection>[K]; }]: { [K in keyof NamedEntityState<E, Collection>]: NamedEntityState<...>[K]; }[K]; }> | PartialStateUpdater<...>'.
  Type 'PartialStateUpdater<NamedEntityState<E, Collection>>' is not assignable to type 'PartialStateUpdater<{ [K in keyof { [K in keyof Name
dEntityState<E, Collection>]: NamedEntityState<E, Collection>[K]; }]: { [K in keyof NamedEntityState<E, Collection>]: NamedEntityState<...>[K]; }[K]; }>'.
    Types of parameters 'state' and 'state' are incompatible.
      Type '{ [K in keyof { [K in keyof NamedEntityState<E, Collection>]: NamedEntityState<E, Collection>[K]; }]: { [K in keyof NamedEntityState<E, Collection>]: NamedEntityState<...>[K]; }[K]; }' is not assignable to type 'NamedEntityState<E, Collection>'.
        Type 'string' is not assignable to type 'keyof NamedEntityState<E, Collection>'.
          Type 'string' is not assignable to type 'keyof NamedEntityState<E, Collection>'.
            Type '"entityMap"' is not assignable to type '`${Collection}${Capitalize<K>}` | `${Collection}EntityMap` | `${Collection}Ids`'. [plugin angular-compiler]

https://stackblitz.com/edit/vitejs-vite-nuijcczs?file=src%2Fmain.ts

Expected behavior

Collection extends string generic could be used to make this feature type-safe and allow method naming like in
ngrx-toolkit withDataService

Versions of NgRx, Angular, Node, affected browser(s) and operating system(s)

"@ngrx/signals": "^19.0.0",

Other information

No response

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

  • Yes
  • No

Note: This is not a regression, the same behavior is present in NgRx Signals v18.

I wonder if it is the same issue as me, or similar ? If it is, I'll mark it as duplicate.

I wonder if it is the same issue as me, or similar ? If it is, I'll mark it as duplicate.

No, this issue is specifically about named collections of entities and their types. So this is compile time issue rather than runtime.

So far nailed this to this small example:

      const state : NamedEntityState<User, Collection> = undefined as any;
      const partialState : Partial<NamedEntityState<User, Collection>> = state;

with error:

TS2322: Type NamedEntityState<User, Collection> is not assignable to type Partial<NamedEntityState<User, Collection>>
Type keyof NamedEntityState<User, Collection> is not assignable to type keyof EntityState<Entity>
Type `${Collection}EntityMap` | `${Collection}Ids` is not assignable to type keyof EntityState<Entity>
Type `${Collection}EntityMap` is not assignable to type keyof EntityState<Entity>
Type `${string}EntityMap` is not assignable to type keyof EntityState<Entity>