Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

angular

ngrx

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?

like image 886
M. Lee Avatar asked Oct 09 '19 16:10

M. Lee


1 Answers

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.

like image 116
berwyn Avatar answered Nov 20 '22 15:11

berwyn