NgRx: how do I declare the explicit type of an action created by action creator?

Viewed 193

After starting a new application and using NgRx's new action creator pattern, I have found myself missing having an explicit type for an action. For example when I'm testing a service, I would like to know that it dispatched the correct action with the correct properties.

How do I go about this while retaining type safety in TypeScript?

An example:

// What should the '???' in the following line be?
spyOn(store, "dispatch").and.callFake((action: ???) => {
  expect(action.type).toBe(fetchProductStructureAction.type);
  // TypeScript complains here if I don't add the correct type to action
  expect(action.property).toBe(expectedProperty); // <--
})
2 Answers

You can put there Action from ngrx/store.

this one works for sure.

spyOn(store, 'dispatch').and.callFake((action: Action) => {
  expect(action).toEqual(jasmine.objectContaining({
    type: fetchProductStructureAction.type,
    property: expectedProperty,
  }));
});

if you want to keep the original type in the callback then you need to cast method to any, but then it brings to the case with ReturnType for creator functions.

spyOn(store, "dispatch" as any).and.callFake((action: MyActionCreatorFunction) => {
  expect(action.type).toBe(fetchProductStructureAction.type);
  expect(action.property).toBe(expectedProperty);
})

As Luis Aceitune mentioned, this works:

ReturnType<typeof myActionCreator>

Example:

export const loadDataAction = createAction('[Example] Load Data', props<{ id: string }>());

type LoadDataAction = ReturnType<typeof loadDataAction>;

enter image description here

Related