如何使用 catchError() 并且仍然返回带有 rxJs 6.0 的类型化 Observable?

Posted

技术标签:

【中文标题】如何使用 catchError() 并且仍然返回带有 rxJs 6.0 的类型化 Observable?【英文标题】:How do I use catchError() and still return a typed Observable with rxJs 6.0? 【发布时间】:2018-10-19 02:08:58 【问题描述】:

cd所以我正在尝试将我的一些 Angular 5 代码迁移到 6,并且我了解 rxjs 使用 .pipe() 运算符工作所需的大部分更改。它可以像您期望的“pipable”操作一样工作。

但是,catchError() 的行为不同于 .catch() 运算符。在 rxjs 6 之前,我使用 .catch() 运算符将错误输入转换为一致的错误对象,然后可以在 `.subscribe() 中捕获该对象。

getAlbums(): Observable<Album[]> 
     return this.httpClient.get<Album[]>(this.config.urls.url("albums"))
           .map(albumList => this.albumList = albumList)
           .catch(new ErrorInfo().parseObservableResponseError);            
    

new ErrorInfo().parseObservableResponseError 是一个函数,它将错误对象作为输入,并将输入错误解析为具有规范化对象的更简单的错误对象。捕获返回Observable&lt;any&gt;

parseObservableResponseError(response): Observable<any> 
    let err = new ErrorInfo();
    ...
    return Observable.throw(err);        

这对于轻松处理 rxjs5 上的错误非常有用 - 错误基本上被捕获为管道的一部分,然后抛出一个众所周知的错误结构,可以捕获 .subscribe() 错误函数。

但是,将相同的代码移动到 rxjs 6 并使用 .pipe() 我正在尝试执行以下操作:

getAlbums(): Observable<Album[]> 
    return this.httpClient.get<Album[]>(this.config.urls.url("albums"))
                .pipe(
                    map(albumList => this.albumList = albumList),
                    catchError(new ErrorInfo().parseObservableResponseError)                        
                );           

但这不起作用,因为 catchError 现在将Observable&lt;any&gt; 的结果返回到管道中,这不是我想要的。本质上,我只是想像以前一样重新抛出任何错误。

错误 TS2322:类型 'Observable' 不能分配给类型 'Observable'

如何模拟老算子.catch()behavior?

更新:

在解决了这个问题之后,显示的代码刚刚开始工作,没有给我一个构建错误。老实说,我不知道为什么它之前失败并显示错误消息,但现在正在工作。 @cartant 在 cmets 中的建议是一种明确的方式来指定结果,并且效果也很好。

【问题讨论】:

如果你只是抛出新的 ErrorInfo()。 parseObservableResponseError(e) 而不是返回它? 为什么不 catchError((e:any)=> return Observable.of( success: false, error: true ));?或 catchError((e:any)=> return Observable.throw(e.error))) @Eliseo 这偶尔会起作用,但主要问题是你会得到一个返回类型,它是 observable 的原始类型(可能是 HttpResponse)和这个“成功/失败”结构的联合。即,如果您继续使用链,您将拥有HttpResponse | success: boolean, error: any 。然后,您需要在它之后添加一个额外的“映射”来规范化类型。我已经尝试过了,这是一个巨大的痛苦。 catchError 的重点是如果没有错误就不会调用它! 【参考方案1】:

您应该能够显式指定catchError 的类型参数,以表明它不会返回发出值的可观察对象——也就是说,它将返回Observable&lt;never&gt;——并且总是会抛出:

getAlbums(): Observable<Album[]> 
    return this.httpClient.get<Album[]>(this.config.urls.url("albums"))
        .pipe(
            map(albumList => this.albumList = albumList),
            catchError<Album[], never>(new ErrorInfo().parseObservableResponseError)
        );           

这样做会看到从pipe 调用推断的类型为Observable&lt;Album[]&gt;

【讨论】:

catchError 应该真的有一个重载签名,以便如果传递的函数的返回类型是 never 则推断出正确的结果 - 即总是抛出。我想是时候创建另一个 PR了。

以上是关于如何使用 catchError() 并且仍然返回带有 rxJs 6.0 的类型化 Observable?的主要内容,如果未能解决你的问题,请参考以下文章

在 catchError 之后不会执行 redux-observable

在 catchError 中发出多个操作 - Redux Observable

NestJS:拦截地图和catchError

从角度服务通过管道传输时,rxjs catchError 不起作用

从ngrx效果调用API时捕获错误

StreamProvider<User> 监听的 _MapStream<FirebaseUser, User> 抛出异常,但未提供`catchError`