Property 'payload' is missing in type 'Action' but required in type 'AddItemAction'

Viewed 3099

I have been trying to create a sample application to learn ngrx, my application has only one 'Action' ADD_ITEM and it has a reducer function which does operations on the state based on the action types.

shopping.actions.ts

 import { Action } from '@ngrx/store'
 import {ShoppingItem} from '../models/shopping-item.model'

 export enum ShoppingActionTypes{
     ADD_ITEM = '[SHOPPING] Add Item'
 }

 export class AddItemAction implements Action {
     readonly type = ShoppingActionTypes.ADD_ITEM

     constructor(public payload: ShoppingItem) { }
 }

 export type ShoppingAction = AddItemAction;

shopping.reducer.ts

//   import { ShoppingAction, ShoppingActionTypes } from "../actions/shopping-actions";
  import { ShoppingActionTypes, ShoppingAction } from "../actions/shopping.actions";

  import { ShoppingItem } from '../models/shopping-item.model';


const initialState: Array<ShoppingItem> = [
  {
    id: "1775935f-36fd-467e-a667-09f95b917f6d",
    name: 'Diet Coke',
  }
];

export function ShoppingReducer(state: Array<ShoppingItem> = initialState, action: ShoppingAction) {
  switch (action.type) {
    case ShoppingActionTypes.ADD_ITEM:
      return [...state, action.payload];

    default:
      return state;
  }
}

The issue occurs in app.module.ts

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StoreModule } from '@ngrx/store';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ShoppingReducer } from './store/reducers/shopping.reducer'
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    StoreModule.forRoot({
      shopping: ShoppingReducer
    }),
    
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

ERROR

Error: src/app/app.module.ts:16:7 - error TS2322: Type '(state: ShoppingItem[] | undefined, action: AddItemAction) => ShoppingItem[]' is not assignable to type 'ActionReducer<ShoppingItem[], Action>'.
  Types of parameters 'action' and 'action' are incompatible.
    Property 'payload' is missing in type 'Action' but required in type 'AddItemAction'.

16       shopping: ShoppingReducer
         ~~~~~~~~

  src/app/store/actions/shopping.actions.ts:11:18
    11      constructor(public payload: ShoppingItem) { }
                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    'payload' is declared here.

Thanks!

2 Answers

I was watching the same tutorial, and it's likely that your angular/ngrx versions are newer. In the latest version of NgRx (currently v12.2.0 as of July 2021), there are factory methods for creating actions and reducers.

The action using createAction:

import { createAction, props } from "@ngrx/store";
import { ShoppingItem } from "../models/shopping-item.model";

export const AddItemAction = createAction(
  '[SHOPPING] Add Item',
  props<{payload: ShoppingItem}>()
);

And createReducer

import { Action, createReducer, on } from '@ngrx/store';
import { AddItemAction } from '../actions/shopping.actions';
import { ShoppingItem } from '../models/shopping-item.model';

const reducer = createReducer(
   initialState,
   on(AddItemAction, (state, action) => {
      return [...state, action.payload]
   })
);

export function ShoppingReducer(state: Array<ShoppingItem> | undefined, action: Action) {
  return reducer(state, action);
}

Just change the signature of your reducer from (..., ShoppingAction) to (..., Action):

export function ShoppingReducer(state: Array<ShoppingItem> = initialState, action: Action) {
  switch (action.type) {
    case ShoppingActionTypes.ADD_ITEM:
      return [...state, (action as ShoppingAction).payload];

    default:
      return state;
  }
}
...

The StoreModule.forRoot(...) seems to expect this signature.

A little side-effect is that we need to cast the action into a ShoppingAction in case of an ShoppingActionTypes.ADD_ITEM type in line 4 of the code snippet.

Related