Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use catchError() and still return a typed Observable with rxJs 6.0?

cdSo I'm trying to migrate some of my Angular 5 code to 6, and I understand most of the changes required for rxjs to work using the .pipe() operator. It works as you would expect for 'pipable' operations.

However, the behavior of catchError() is different than the .catch() operator. Prior to rxjs 6 I used the .catch() operator to transform the error input into a a consistent error object that can then be caught in the `.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 is a function that takes a error object as input and parses the input error into a simpler error object with a normalized object. Catch returns Observable<any>:

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

This worked great for easily handling errors up rxjs5 - errors basically are captured as part of the pipeline and then throw a well known error structure that can be captured .subscribe() error function.

Moving that same code to rxjs 6 however and using .pipe() I am trying to do the following:

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

However this doesn't work because catchError now returns a result of Observable<any> into the pipeline, which is not what I want here. In essence I just want to re-throw any errors as I did before.

error TS2322: Type 'Observable<{} | Album[]>' is not assignable to type 'Observable'

How do simulate the old operator .catch()behavior?

Update:

After mucking around with this a bit more, the code as shown just started working without giving me a build error. Honestly I have no idea why it failed with the error message before, but is working now. The suggestion by @cartant in the comments is an explicit way to specify the result and that works as well.

like image 794
Rick Strahl Avatar asked May 09 '18 03:05

Rick Strahl


People also ask

What does catchError return?

catchError method Null safety Handles errors emitted by this Future. This is the asynchronous equivalent of a "catch" block. Returns a new Future that will be completed with either the result of this future or the result of calling the onError callback.

Where do I put catchError RxJS?

The right way to handle the RxJS error is by putting the “catchError” inside the http. get “pipe”. It will end the http. get observable but that doesn't matter because it is a finite observable anyways and only emits one value.

What is catchError in RxJS?

RxJS catchError() operator is an error-handling operator used to handle and take care of catching errors on the source observable by returning a new observable or an error.

How does a catchError work?

The catchError operator takes as input an Observable that might error out, and starts emitting the values of the input Observable in its output Observable. If no error occurs, the output Observable produced by catchError works exactly the same way as the input Observable.


1 Answers

You should be able to explicitly specify the type parameters to catchError to indicate that it won't return an observable that emits a value - that is, it will return Observable<never> - and will always throw:

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

Doing so will see the type inferred from the pipe call to be Observable<Album[]>.

like image 149
cartant Avatar answered Oct 26 '22 23:10

cartant