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"-程序。
感谢和欢呼!
可能性的集合
这是我们目前所做的,也是来自评论和答案的想法。
- 在大多数情况下,这可能不是操作的问题
switchMap
参数 可能解构错误
- 其中一个 RxJS 运算符未导入
- 错误的参数和 return 服务中的值可能是原因
- 服务和操作类型不一致也可能是原因
- 如果没有任何帮助并且您确定没有问题:重新加载 TypeScript
我们仍然希望有一个技巧来分解错误消息。
实际上你需要把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/lodash
。 npm 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。
在使用 NgRX 8 时,我和我的同事在实现效果时经常遇到奇怪的错误消息。
Type 'Observable<unknown>' is not assignable to type 'Observable<Action> | ((...args: any[]) => Observable<Action>)'
与类型问题有关。消息如此不具体,它标志着完整的效果,真是令人讨厌。这个经常出现,真的很难解决。
我们想知道我们是否可以做些什么来快速识别问题,或者我们是否能够以某种方式解构消息。我不是在这里寻找特定的解决方案,而是寻找 "how to quickly determine what's wrong"-程序。
感谢和欢呼!
可能性的集合
这是我们目前所做的,也是来自评论和答案的想法。
- 在大多数情况下,这可能不是操作的问题
switchMap
参数 可能解构错误
- 其中一个 RxJS 运算符未导入
- 错误的参数和 return 服务中的值可能是原因
- 服务和操作类型不一致也可能是原因
- 如果没有任何帮助并且您确定没有问题:重新加载 TypeScript
我们仍然希望有一个技巧来分解错误消息。
实际上你需要把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/lodash
。 npm 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。