@ngrx/reducer: createReducer(), and on() are not being type-safe?
Asked Answered
S

2

9

When using previous versions of ngrx where I didn't use createAction() and createReducer(), it would throw an error if I try to add any additional attributes that were not part of the provided State.

I upgraded the app to Angular 8, and using ngrx 8.3.0 as well. Now it seems like the type safety is not there anymore, even though NGRX documentation points out that most of the type inference will be implemented.

someState.ts

export interface ISampleState {
  id: number
}

someAction.ts

export const request = createAction('[SAMPLE] Request', props<{id: number}>();

someReducer.ts

const initialState: ISampleState = {
  id: null
}

const sampleReducer = createReducer(
  initialState,
  on(SampleActions.request, (state, { id }) => {
    return {
      ...state,
      id,
      // Below would previously complain since only `id` is defined in the `ISampleState`
      thisShouldNormallyComplain: 'but it does not'
    }
  }
);

// AOT purposes
export function reducer(state: ISampleState | undefined, action: Action): ISampleState {
  return sampleReducer(state, action);
}

After actually running the code, I would see via DevTools that the store is indeed populated with this unwarranted attribute.

My biggest concern is when I have a typo in the reducer within the return block, it would also not complain.

i.e. If I accidentally type

return {
   ...state,
   Id: id  //should be `id`
}

it would be difficult to locate the error since it compiles just fine without complaints.

Any ideas?

Scandian answered 9/10, 2019 at 16:40 Comment(1)
Turns out this is a known issue from TypeScript's end so you can refer to this issue for tracking.Scandian
N
8

Having played with this a bit, it seems like this is a problem with TypeScript! createReducer ultimately creates an ActionReducer<S, A> which has a signature of (state: S | undefined, action: A) => S.

In this case, TypeScript seems to allow any callable that satisfies this signature to satisfy the argument, even if the returned type has more properties than S does. I've filed this bug against the compiler because to me that doesn't seem to be correct behaviour.

Nectarine answered 9/10, 2019 at 18:13 Comment(0)
J
0

Try this:

const retVal: ISampleState = {
   ...state,
   Id: id  //should be `id`
}
return retVal;

This produces an error for Id.

Journalist answered 18/5, 2024 at 19:22 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Proximal

© 2022 - 2025 — McMap. All rights reserved.