NGRX: TypeError: Actions must have a type property

20.8k Views Asked by At

Being new to ngrx I am facing an exception and not sure why...

I am trying to dispatch an action and handle it in an effect, but I keep getting the error: TypeError: Actions must have a type property

Actions:

export const TEST_ACTION = 'test_action';
export class TryTest implements Action {
    readonly type = TEST_ACTION;

    constructor(public playload: any) {
    }
}
export type MyActions = TryTest;

Effects:

import * as MyActions from "./myactions.actions";

@Injectable()
export class MyEffects {
    @Effect()
    testEffect = this.actions$
        .ofType(MyActions.TEST_ACTION)
        .map((action: MyActions.TryTest) => {
            return 'something'
        });

    constructor(private actions$: Actions) {}
}

Component:

this.store.dispatch(new MyActions.TryTest({ name: 'test' }));

I am using:

effects: 4.0.5 and store: 4.0.3

4

There are 4 best solutions below

1
On BEST ANSWER

If this helps someone else starting...Turns out I was not returning the Action that ngrx is expecting in the map operator.

1
On

In my case I have written wrong Action class, Query.action.ts file is having all the actions for the store, in here I have made a silly mistake.

in the line readonly type = QueryActionTypes.SaveQuery; instead of assiging the variable type, I have just defined it.

I have used colon ":" instead of equal "=".

I have written readonly type : QueryActionTypes.SaveQuery;

export enum QueryActionTypes {
 SaveQuery = '[Query] Save Query'
}

export class SaveQuery implements Action {
   readonly type = QueryActionTypes.SaveQuery;
   constructor(public payload: { Query : Query}) {}
}

export type QueryActions = SaveQuery

So ngrx unable to find property type in SaveQuery class (because I have used colon : instead of equal =) which implements Action class. This Action class needs type property

0
On

by default all effects you create are supposed to emitt an action which is dispatched to the store. Thus, as result from effect function, you need to return type Observable<Action> where Action is an interface from @ngrx/store:

export interface Action {
    type: string;
}

So mapping to object with property type will work:

 @Effect() testEffect = this.actions$
             .ofType(MyActions.TEST_ACTION)
             .map((action: MyActions.TryTest) => {
                    return {type:'action_for_test_effect'}
              });

In this case, you should support action_for_test_effect in your reducer.

If you don't need to dispatch any action from effect, you can disable it by adding config object to effect:

@Effect({dispatch: false}) testEffect = this.actions$
                 .ofType(MyActions.TEST_ACTION);
1
On

because effect must return an action at the end. so you have two choices:

  1. return a {type: string} object
  2. return a new Action()

    import * as MyActions from "./myactions.actions";
    
    @Injectable()
    export class MyEffects {
        @Effect()
        testEffect = this.actions$
            .ofType(MyActions.TEST_ACTION)
            .map((action: MyActions.TryTest) => {
                return {type:'your_action'}
            });
    
        constructor(private actions$: Actions) {}
    }