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 answers

1
Thibs 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
ddc 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
kuceraf 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
Engalar Liu 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) {}
    }