NgRX effects - Type 'Observable<unknown>' is not assignable to type 'Observable<Action>'

37,062

Solution 1

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

Still 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.

Solution 2

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.

Solution 3

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>>

Solution 4

Actually you need to treat actions created by createAction as a function and call it to return the action object. Check this desc. So your of(addCommentFailed) should be of(addCommentFailed()).

Solution 5

What fixed it for me was adding Observable<Action> as the return type for the function that's passed into createEffect. Ex:

addComment$ = createEffect((): Observable<Action> =>
  this.actions$.pipe(
    ...
  ),
);
Share:
37,062
Felix Lemke
Author by

Felix Lemke

We develop high performance enterprise web applications using latest technologies with focus on user experience. Contact us if we can help solving your software problem or if you want us to share our knowledge with your team by workshops and trainings. "We do not know what the rules of the game are; all we are allowed to do is to watch the playing." R. Feynman

Updated on July 09, 2022

Comments

  • Felix Lemke
    Felix Lemke almost 2 years

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

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

    It is related to type issues. It is really annoying that the message is so unspecific and it marks the complete effect. This appears frequently and is really hard to resolve.

    enter image description here

    We are wondering if there is something we can do in order to quickly identify the problems or if we are able to destructure the message in some way. I am not looking for a specific solution here, but more for a "how to quickly determine what's wrong"-procedure.

    Thanks and cheers!

    Collection of possibilities

    It is what we have done so far and also ideas from comments and answers.

    • In most cases it is probably not an issue with actions
    • It can be a wrong destructuring for the switchMap parameter
    • One of the RxJS operators is not imported
    • Wrong parameters and return value in the service can be the reason
    • Inconsistent types in service and action can be the reason as well
    • If nothing helps and you are sure, there is nothing wrong: Reload TypeScript

    We are still hoping for a trick to break down the error message.

  • Felix Lemke
    Felix Lemke almost 5 years
    Thanks for your answer, I know that I have to execute the function but it is not causing the error. As I mentioned in the comments before, I am also not looking for a specific solution of the screenshot but a general "quickly determine what's wrong"-instruction.
  • KiraAG
    KiraAG almost 5 years
    Ok. Now I get it. But I Believe there can be no one general instruction. I would suggest to with the created actions return types. This suggestion is based on this test spec, you can see a similar error message being asserted.Also check this
  • Felix Lemke
    Felix Lemke almost 5 years
    Hi @mr.vea, thanks for your answer :) I am going to have a look at this today.
  • Felix Lemke
    Felix Lemke almost 5 years
    Hi, thanks for your answer, I am going to test your strategy today and let you know :)
  • Felix Lemke
    Felix Lemke over 4 years
    Commenting out createEffect(() => works flawlessly, thanks a lot!
  • Andrew Allen
    Andrew Allen over 4 years
    @ngfelixl not quite flawlessly, if I put my project into a stricter typescript mode ("strict": true in tsconfig.json) then this approach does not always work.
  • Felix Lemke
    Felix Lemke over 4 years
    Agreed, but I mean flawlessly compared to the original problem.
  • Travis Peterson
    Travis Peterson over 4 years
    I believe this to be the correct answer. your catchError method is returning the function and not the value of the function. Adding parens to all actions is required in NgRX 8.
  • Felix Lemke
    Felix Lemke over 4 years
    I agree, this error appears if one of the operators or observable "constructors" are not imported. But it also appears if types are not matching and in several other cases. Thanks a lot for your answer and I think there is someone who is interested in your solution. :)
  • Jan Klan
    Jan Klan about 3 years
    You just saved me a lot of head-scratching. Thank you.
  • Jimmy Geers
    Jimmy Geers almost 3 years
    Thank you so much you saved me so much time! :)
  • Zaben
    Zaben over 2 years
    does anyone had same error with 'switchMap/MergeMap' even after fix of the createEffect error?
  • Andrew Allen
    Andrew Allen over 2 years
    @Zaben see the Additional note above - very likely you're mapping to a non-action and not including { dispatch: false }. If you're still struggling, ask a new question