cartant/ts-action

Function calls are not supported in decorators

mihalcan opened this issue · 3 comments

Reducer function fail during AOT compilation.
ng build --prod with a reducer function throws the following exception:

ERROR in src\app\app.module.ts(34,25): Error during template compile of 'AppModule'
  Function calls are not supported in decorators but 'reducer' was called in 'reducers'
    'reducers' references 'myReducer' at src\app\reducers\index.ts(17,10)
      'myReducer' calls 'reducer' at src\app\core\reducers\my.reducer.ts(15,26).

Sample code:

import { on, reducer } from 'ts-action';

export const myReducer = reducer<State>([
    on(GetAllSuccess, (state, { payload }) => ({ ...state, collection: payload }))
  ], initialState
);

The same logic using switch statement is working fine:

export function myReducer(state: State = initialState, action: typeof MyActions): State {
  switch (action.type) {
    case GetAllSuccess.type:
      return { ...state, collection: action.payload };
    default:
      return state;
  }
}

package.json

    "@angular/common": "6.0.6",
    "@angular/compiler": "6.0.6",
    "@angular/core": "6.0.6",
    "@ngrx/effects": "^6.0.1",
    "@ngrx/store": "^6.0.1",
    "@ngrx/store-devtools": "^6.0.1",
    "ts-action": "^6.0.2",
    "ts-action-operators": "^7.0.0",
// the remaining packages are omitted

    "typescript": "2.7.2",

Presumably, you are configuring your store something like this:

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { counterReducer } from './counter';

@NgModule({
  imports: [StoreModule.forRoot({ count: counterReducer })],
})
export class AppModule {}

You need to inject the reducers instead:

import { NgModule, InjectionToken } from '@angular/core';
import { StoreModule, ActionReducerMap } from '@ngrx/store';

import { SomeService } from './some.service';
import * as fromRoot from './reducers';

export const REDUCER_TOKEN = new InjectionToken<
  ActionReducerMap<fromRoot.State>
>('Registered Reducers');

export function getReducers(someService: SomeService) {
  return someService.getReducers();
}

@NgModule({
  imports: [StoreModule.forRoot(REDUCER_TOKEN)],
  providers: [
    {
      provide: REDUCER_TOKEN,
      deps: [SomeService],
      useFactory: getReducers,
    },
  ],
})
export class AppModule {}

Thanks Nicolas, it resolved the problem.
It would be great if this information (+ a little bit of explanation) is added to the documentation.

It would be great if this information (+ a little bit of explanation) is added to the documentation.

I'll add it to my TODO list.