NgRX 效果 - 类型 'Observable<unknown>' 不可分配给类型 'Observable<Action>'

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

在使用 NgRX 8 时,我和我的同事在实现效果时经常遇到奇怪的错误消息。

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

与类型问题有关。消息如此不具体,它标志着完整的效果,真是令人讨厌。这个经常出现,真的很难解决。

我们想知道我们是否可以做些什么来快速识别问题,或者我们是否能够以某种方式解构消息。我不是在这里寻找特定的解决方案,而是寻找 "how to quickly determine what's wrong"-程序。

感谢和欢呼!

可能性的集合

这是我们目前所做的,也是来自评论和答案的想法。

我们仍然希望有一个技巧来分解错误消息。

实际上你需要把createAction创建的action当作一个函数来调用它给returnaction对象。检查此 desc。所以你的 of(addCommentFailed) 应该是 of(addCommentFailed()).

我也遇到过类似的错误。

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

我确定可能发生的事情的最快方法是在 | 分隔符之后。 类型通常是 Observable<{something}>Observable<{something | another}>。有一个 | 分隔符,第二项不是 Observable。这可能是问题所在。

例如,如果 observable 期望有 Observable<Action>,但有一些管道运算符 returns 除了 Observable<Action>。意外的类型会附加到错误消息中的预期类型,因为对于 Observable,T 在 ((...args: any[]) => Observable<Action>)

中不存在

我对消息的解读是

对象的内部类型未知,因为我们不知道期望的类型 Observable<Action> = Action((...args: any[]) => Observable<Action>) = 未知

如果问题不是很明显,我只是将每个管道运算符一一注释掉,看看错误是否解决。如果是,现在我知道这个运算符是问题所在,然后我专注于运算符并找到问题。

我有兴趣阅读其他用户的回复。这两种方式总是给我指明正确的方向。

我遇到了完全相同的问题,在我的情况下,这是因为错误放置大括号和缺少导入。

这是我调试和解决它的方法。

将内部可管道函数拆分为单独的函数。这对我来说是最重要的一步,因为来自 vscode 的复杂语法和自动完成大括号,有时大括号存在于错误的位置并且不容易找到。这也解决了几乎所有其他问题(缺少导入、不正确的 return 类型等),因为要调试的代码要小得多,并且 vscode 会突出显示子函数中的这个个别错误。

这是我之前的

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

将其更改为以下

 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()));
    }

我从这种方法中得到的另一个好处是不会触发内部管道上的 catchError 块(根据效果示例,它应该有效)。因此必须将它包含在外部可管道块中。这里错误被捕获并按预期工作。但仍在弄清楚为什么它不起作用。

总结一下,登录服务执行以下操作(抛出错误或 return Observable of true)

//login.service.ts

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

希望这对您有所帮助。

快速版
注释掉 createEffect(() =>,
修复您的 IDE (VSCode) 标记的错误,
添加 createEffect(() => 回来。

备选方案 - 像下面这样重写也有效

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

额外

进行了以上操作后还是报错? 类型检查正确地完成了它的工作并告诉你你应该映射到一个 Observable<Action> 或纯粹的副作用效果添加第二个参数 { dispatch: false } (即不分派一个动作)。请参阅 NgRx Effects Docs


较早的答案(使用 @Effect 是不必要的,也不是必需的)

我发现最简单的调试方法是使用 @Effect 装饰器以版本 7 的方式编写,完成后使用 createEffect.

重写

所以要调试:

  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'] }))
    )
  )

将无用的错误写为(添加装饰器,删除 createEffect(() =>,删除最后一个括号),

@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'] }))
)

现在我们得到错误

Cannot find name 'SwitchMap'

其次是

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

解决这个问题

@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'] })))
)

现在用 NgRx 8 术语重写。不漂亮但有效。

我遇到这个问题是因为这里缺少导入 'of' 运算符

// 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 })))
        )
      )
    )
  );
...

我已经通过在顶部添加这行代码修复了它

// events.effects.ts

import { Observable, of } from 'rxjs';

...

如果处理这个问题并使用官方 ngrx 8 示例。

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

简单快捷的解决方案可以是 "any" 类型。

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

不要忘记 rxjs 运算符、可观察对象的导入。

如果处理动作负载 - 道具,请定义动作类型。

ofType<MySuperActions>

ofType<ReturnType<typeof myAction>>

我今天 运行 遇到了类似的问题(相同的错误消息),这是因为 TypeScript 无法正确推断 Array#flatMap. I assume it will be the same for Array#map, RxJS#map 的 return 类型或任何不存在的数组已明确键入。

这是崩溃的代码:

this.actions$.pipe(
    ofType(ActionType),
    switchMap((action) => {
        return action.cart.flatMap((cartItem: CartItem) => {
            if (x) {
                return [
                    ActionCreator1(params1),
                    ActionCreator2(params2)
                ];
            } else {
                return [];
            }
        }
    })
)

所以我得到了同样的错误信息:

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

要修复它,我只需要告诉 TypeScript 我的映射函数 returned 了一个 Action 的数组:

import { Action } from '@ngrx/store';
...
    switchMap((action) => {
        return action.cart.flatMap((cartItem: CartItem) : Action[] => {
...

此外,使用 Action[] 键入比使用 any 更安全!

就我而言,我在其中一个 rxjs 运算符中使用了一个 lodash 运算符。原来,我没有@types/lodashnpm i -D @types/lodash之后,我的问题就解决了

我为这个问题苦苦挣扎了一段时间,最后才发现 VS 代码自动从某个库中导入 Observable 而不是 rxjs

希望这可以避免不必要的撞头。

我在我的项目中遇到了这个错误并通过添加这个导入解决了它:

import { Observable, of as observableOf, of } from 'rxjs';

为我解决的问题是将 Observable<Action> 添加为传递给 createEffect 的函数的 return 类型。例如:

addComment$ = createEffect((): Observable<Action> =>
  this.actions$.pipe(
    ...
  ),
);

对我有用的方法:重新启动 Visual Code Studio。