NgRX effects - Type 'Observable' is not assignable to type 'Observable'

前端 未结 9 1088
你的背包
你的背包 2020-12-16 10:12

While working with NgRX 8 my colleagues and me are frequently facing a weird error message when implementing the effects.

Type \'Observable

相关标签:
9条回答
  • 2020-12-16 10:15

    I had this issue because of missing import 'of' operator here

    // events.effects.ts
    ...
    
    getEvents$: Observable<Action> = createEffect(
        () => this.actions$.pipe(
          ofType(EventsActions.getEvents),
          switchMap(action =>
            this.eventService.getEvents().pipe(
              map(events => EventsActions.getEventsSuccess({ events })),
              catchError(error => of(EventsActions.getEventsError({ error })))
            )
          )
        )
      );
    ...
    

    I've fixed it by adding this line of code at the top

    // events.effects.ts
    
    import { Observable, of } from 'rxjs';
    
    ...
    
    0 讨论(0)
  • 2020-12-16 10:17

    In my case, I used a lodash operator inside one of the rxjs operators. Turned out, I didn't have @types/lodash. After npm i -D @types/lodash, my problem was solved.

    0 讨论(0)
  • 2020-12-16 10:19

    Quick version
    comment out createEffect(() =>,
    fix errors that your IDE (VSCode) flags up,
    add createEffect(() => back in.

    Alternative - rewriting like the following also works

    someEffect$ = createEffect(() => {
      return this.actions$.pipe(
        ...
      )
    })
    

    Additional

    No errors after doing the above? Type-checking is doing it's job correctly and telling you that you should be mapping to an Observable<Action> or for a purely side-effect effect adding the second argument { dispatch: false } (i.e. not dispatching an action). See the NgRx Effects Docs


    Older Answer (using @Effect is unneccessary and is not required)

    The easiest way I've found to debug is to write in a version 7 manner with the @Effect decorator and once done rewrite using createEffect.

    So to debug:

      navigateToDashboard$ = createEffect(() =>
        this.actions$.pipe(
          ofType(teamActions.CREATE_SUPERVISOR_GROUP_SUCCESS),
          map((action: teamActions.CreateSupervisorGroupSuccess) => action.payload),
          map((team: Team) => team.TeamID),
          SwitchMap(id => new routerActions.Go({ path: ['/team', id, 'populate'] }))
        )
      )
    

    which gives the non-helpful error write as (add decorator, delete createEffect(() =>, delete final bracket),

    @Effect()
    navigateToDashboard$ = this.actions$.pipe(
        ofType(teamActions.CREATE_SUPERVISOR_GROUP_SUCCESS),
        map((action: teamActions.CreateSupervisorGroupSuccess) => action.payload),
        map((team: Team) => team.TeamID),
        SwitchMap(id => new routerActions.Go({ path: ['/team', id, 'populate'] }))
    )
    

    Now we get error

    Cannot find name 'SwitchMap'
    

    Followed by

    Type 'Go' is not assignable to type 'ObservableInput<any>'
    

    Fixing this gives

    @Effect()
    navigateToDashboard$ = this.actions$.pipe(
        ofType(teamActions.CREATE_SUPERVISOR_GROUP_SUCCESS),
        map((action: teamActions.CreateSupervisorGroupSuccess) => action.payload),
        map((team: Team) => team.TeamID),
        switchMap(id => of(new routerActions.Go({ path: ['/team', id, 'populate'] })))
    )
    

    Now rewrite in NgRx 8 terms. Not pretty but works.

    0 讨论(0)
  • 2020-12-16 10:26

    In case of dealing with this problem and using official ngrx 8 example.

    loadMovies$ = createEffect(() => this.actions$.pipe(
        ofType('[Movies Page] Load Movies'),
        mergeMap(() => this.moviesService.getAll()
          .pipe(
            map(movies => ({ type: '[Movies API] Movies Loaded Success', payload: movies })),
            catchError(() => EMPTY)
          ))
       )
    );
    

    Easy and fast solution can be putting "any" type.

    loadMovies$: any = createEffect((): any => this.actions$.pipe(
        ofType('[Movies Page] Load Movies'),
        mergeMap(() => this.moviesService.getAll()
          .pipe(
            map(movies => ({ type: '[Movies API] Movies Loaded Success', payload: movies })),
            catchError(() => EMPTY)
          ))
       )
    );
    

    Do not forget imports for rxjs operators, observables.

    In case of dealing with action payload - props, define an action type.

    ofType<MySuperActions>
    

    or

    ofType<ReturnType<typeof myAction>>
    
    0 讨论(0)
  • 2020-12-16 10:34

    I have seen similar error as well.

    Type 'Observable<unknown>' is not assignable to type 'Observable<Action> | ((...args: any[]) => Observable<Action>)'
    

    The quickest way I identify what may have happened is after | separator. The type is usually Observable<{something}> or Observable<{something | another}>. There is a | separator and the second item is not an Observable. This is maybe the problem.

    If for example the observable expects to have Observable<Action>, but there is some pipe operator returns something other than Observable<Action>. The unexpected type will appended to the expected type in the error message, because for Observable, T does not exist in ((...args: any[]) => Observable<Action>)

    my interpretation of the message is

    Internal type of an object is unknown, because we do not know which type to expect Observable<Action> = Action or ((...args: any[]) => Observable<Action>) = unknown

    if the problem is not immediately obvious, I just comment out the each pipe operator one by one and see if error goes way. If it does, now I know this operator is the problem, than I focus on operator and find the problem.

    I am interested to read other users replys. Those two way always points me in the right direction.

    0 讨论(0)
  • 2020-12-16 10:36

    I had the exact same issue and in my case it was because of wrongly placed braces and a missing import.

    Here is what I did to debug and solve it.

    Split the inner pipe-able function into individual functions. This is the foremost step for me because of the complex syntax and auto complete braces from vscode, sometimes a brace exists in wrong place and it's not easy to find. This also solves almost all other problems (missing imports, incorrect return types etc) as the code to debug is much smaller and vscode highlights this individual error from the sub function.

    This is what I had before

        performLogin$ = createEffect(() => 
           this.actions$.pipe(
               ofType(performLogin),
               mergeMap(() => this.loginService.performLogin().pipe(
                   map(() => loginSuccess())
               )))
        );
    
    

    Changed this to below

     performLogin$ = createEffect(() => 
           this.actions$.pipe(
               ofType(performLogin),
               mergeMap(() => this.performLogin()),
               catchError((error ) => { console.log("HELLO"); return EMPTY})
           )
        );
    
        performLogin() {
            return this.loginService.performLogin()
            .pipe(map(() => loginSuccess()));
        }
    
    

    Also a bonus I got from this approach is that the catchError block on the inner pipe does not get triggered (as per effects example it should work). Hence had to include it in the outer pipe-able block. Here the error is caught and works as expected. But still figuring out why it does not work.

    Just to sum it up, the login service does the following (throw error or return Observable of true)

    //login.service.ts
    
    performLogin() : Observable<boolean> {
            throw "Something went wrong";
            //return of(true);
        }
    
    

    Hope this helps.

    0 讨论(0)
提交回复
热议问题