【问题标题】:NgRX effects - Type 'Observable<unknown>' is not assignable to type 'Observable<Action>'NgRX 效果 - 类型 'Observable<unknown>' 不可分配给类型 'Observable<Action>'
【发布时间】:2022-04-11 01:27:13
【问题描述】:

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

类型 'Observable' 不可分配给类型 'Observable | ((...args: any[]) => Observable)'

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

我们想知道是否可以采取一些措施来快速识别问题,或者我们是否能够以某种方式解构信息。我不是在这里寻找特定的解决方案,而是更多地寻找“如何快速确定问题所在”的程序。

感谢和欢呼!

可能性的集合

这是我们迄今为止所做的,也是来自 cmets 和答案的想法。

  • 在大多数情况下,操作可能不是问题
  • switchMap 参数的解构可能是错误的
  • 其中一个 RxJS 运算符未导入
  • 服务中的错误参数和返回值可能是原因
  • 服务和操作类型不一致也可能是原因
  • 如果没有任何帮助并且您确定,没有任何问题:重新加载 TypeScript

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

【问题讨论】:

  • addComment 是什么?
  • addCommentFailed/of(addCommentFailed)的类型是什么?
  • 解决这个问题并不重要,但要以某种方式获得一个通用的方法来处理这个错误。 addCommentcreateAction 方法的返回,可能不是问题所在。 failedsuccess 方法也是 createAction 生成的操作。 failed 不是这里的问题,尽管我没有将失败的操作作为函数执行。
  • 我在本地重新创建了它,没有收到任何错误。您是否检查过您的编辑器工作区是否使用项目打字稿版本?有时 VSCode 开始使用全局安装的 TS 版本。
  • 在ofType参数中,需要将其传递为${your action}.type,如果action是通过createAction创建的

标签: angular typescript ngrx angular8


【解决方案1】:

快速版
注释掉createEffect(() =&gt;,
修复 IDE (VSCode) 标记的错误,
重新添加createEffect(() =&gt;

替代方案 - 如下重写也可以

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

附加

执行上述操作后仍然出现错误? 类型检查正确地完成了它的工作,并告诉您应该映射到 Observable&lt;Action&gt; 或者为了纯粹的副作用添加第二个参数 { 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(() =&gt;,删除最后一个括号),

@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 术语重写。不漂亮但有效。

【讨论】:

  • 注释掉 createEffect(() =&gt; 完美无缺,非常感谢!
  • @ngfelixl 不是很完美,如果我将我的项目置于更严格的打字稿模式("strict": true in tsconfig.json)那么这种方法并不总是有效。
  • 同意,但我的意思是与原始问题相比完美无缺。
  • 你让我省了很多麻烦。谢谢。
  • 即使在 createEffect 错误修复之后,是否有人对“switchMap/MergeMap”有同样的错误?
【解决方案2】:

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

这是我为调试和解决它所做的。

将内部管道功能拆分为单独的功能。这对我来说是最重要的一步,因为 vscode 的复杂语法和自动完成大括号,有时大括号存在错误的位置并且不容易找到。这也解决了几乎所有其他问题(缺少导入、不正确的返回类型等),因为要调试的代码要小得多,并且 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 块不会被触发(根据效果示例,它应该可以工作)。因此必须将它包含在外部可管道块中。在这里,错误被捕获并按预期工作。但仍在弄清楚为什么它不起作用。

总结一下,登录服务做了以下事情(抛出错误或者返回真值的Observable)

//login.service.ts

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

希望这会有所帮助。

【讨论】:

  • 你好,谢谢你的回答,我今天要测试你的策略,让你知道:)
  • 非常感谢您为我节省了这么多时间! :)
【解决方案3】:

如果处理这个问题并使用官方的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)
      ))
   )
);

简单快速的解决方案可以放入“任何”类型。

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

【讨论】:

    【解决方案4】:

    其实你需要把createAction创建的action当成一个函数,调用它返回action对象。检查此desc。所以你的of(addCommentFailed) 应该是of(addCommentFailed())

    【讨论】:

    • 感谢您的回答,我知道我必须执行该功能,但它不会导致错误。正如我之前在 cmets 中提到的,我也不是在寻找截图的具体解决方案,而是一个通用的“快速确定问题所在”的指令。
    • 好的。现在我懂了。但我相信不可能有一个通用的指令。我建议使用创建的操作返回类型。这个建议是基于这个test spec,你可以看到一个类似的错误信息被断言。另外检查this
    • 我相信这是正确的答案。您的 catchError 方法返回的是函数而不是函数的值。在 NgRX 8 中需要为所有操作添加括号。
    【解决方案5】:

    我遇到了这个问题,因为这里缺少 import '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';
    
    ...
    

    【讨论】:

    • 我同意,如果未导入运算符或可观察的“构造函数”之一,则会出现此错误。但是,如果类型不匹配以及在其他几种情况下,它也会出现。非常感谢您的回答,我认为有人对您的解决方案感兴趣。 :)
    【解决方案6】:

    为我解决的问题是将Observable&lt;Action&gt; 添加为传递给createEffect 的函数的返回类型。例如:

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

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        我今天遇到了类似的问题(相同的错误消息),这是因为 TypeScript 无法正确推断 Array#flatMap 的返回类型。我认为Array#mapRxJS#map 或任何未显式键入的数组都是相同的。

        这是崩溃的代码:

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

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

        类型 'Observable' 不可分配给类型 'Observable | ((...args: any[]) => Observable)'

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

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

        另外,使用Action[] 打字比使用any 更安全!

        【讨论】:

          【解决方案9】:

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

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

          【讨论】:

            【解决方案10】:

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

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

            【讨论】:

              【解决方案11】:

              什么对我有用:重新启动 Visual Code Studio。

              【讨论】:

                【解决方案12】:

                我也看到过类似的错误。

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

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

                例如,如果 observable 期望有 Observable&lt;Action&gt;,但有一些管道运算符返回 Observable&lt;Action&gt; 以外的东西。意外类型会附加到错误信息中的预期类型,因为对于 Observable,T 在((...args: any[]) =&gt; Observable&lt;Action&gt;) 中不存在

                我对消息的解释是

                一个对象的内部类型是未知的,因为我们不知道期望Observable&lt;Action&gt; = Action((...args: any[]) =&gt; Observable&lt;Action&gt;) = 未知的类型

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

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

                【讨论】:

                • 嗨@mr.vea,感谢您的回答:) 我今天要看看这个。
                猜你喜欢
                • 2020-07-28
                • 2021-10-28
                • 1970-01-01
                • 2020-01-10
                • 2020-04-17
                • 2020-01-10
                • 1970-01-01
                • 2020-07-29
                • 2018-08-14
                相关资源
                最近更新 更多