lopah elision
lopah elision

Reputation: 49

Understand RxJS catchError

I am new to RxJS and I am unable to figure out how the parameters are being passed:

import { catchError, map, Observable, of } from 'rxjs';


let obs$ = of(1,2,3,4,5);
obs$.pipe(
    map(n => {
        if (n === 4) {
            throw 'bloody hell'
        }
        return n;
    }),
    catchError(handleError())
).subscribe(x => console.log(x));

function handleError() {
    return (err: any, caught: Observable<any>): Observable<string> => {
        console.log('error is ', err);
        return of('I', 'II') ;
    }
}

Output is

$ node build/catch-me.js
1
2
3
error is  bloody hell
I
II

Now when I look at the catchError function it states:

export function catchError<T, O extends ObservableInput<any>>(
  selector: (err: any, caught: Observable<T>) => O
): OperatorFunction<T, T | ObservedValueOf<O>>;

My questions are:

  1. How does the handleError magically get the err and caught values from catchError function? It is not being passed anywhere?
  2. Why is it that the err and caught values are available only in the return function of the handleError?
  3. Are there two types being passed - one is the Type of the observable, the second the ObservableInput?
  4. How is one to understand what is the operaterfunction that is being returned from catchError? Finally one is returning an observable with values I, II.

Upvotes: 2

Views: 307

Answers (2)

Mrk Sef
Mrk Sef

Reputation: 8022

My questions are:

  1. How does the handleError magically get the err and caught values from catchError function? It is not being passed anywhere?

The catchError function doesn't have any direct relationship to the "err and caught value." Well, it does but only statically. It just needs to return a function of the correct type.

Or, if you're Haskell Curry you might say that handleError takes it's arguments separately and you're only seeing the partial application. The ret of the application happens inside catchError Consider the following:

function add(a,b) {
  return a + b;
}
function curry_add(){
  return a => b => a + b;
}

const ten = add(9,1);
const alsoTen = curry_add()(9)(1);

curry_add isn't magically getting any parameters. It's the same as add, but it requires 3 applications before you can get a number out.

  1. Why is it that the err and caught values are available only in the return function of the handleError?

Partial application again, you can think of them as the second application of handleError instead if you want. Giving you those values is the job of the catchError operator, so you perform the first application and the operator performs the second behind the scenes.

  1. Are there two types being passed - one is the Type of the observable, the second the ObservableInput?

The error and the observable that emitted the error.

  1. How is one to understand what is the operaterfunction that is being returned from catchError? Finally one is returning an observable with values I, II.

An OperatorFunction transforms an observable. The pipe function only knows how to deal with OperatorFunctions so every every operator ends up creating an OperatorFunction. So map, tap, switchMap, catchError, etc all have the job of creating an OperatorFunction for you. You can just create one on your own if you want.

for example:

function filterFours(a: Observable<number>): Observable<number> {
  return new Observable(observer => {

    const sub = a.subscribe({
      next: v => {
        if (v != 4) observer.next(v);
      },
      complete: () => observer.complete(),
      error: e => observer.error(e)
    });

    return {
      unsubscribe: () => sub.unsubscribe()
    };

  })
}

of(1,4,2,4,3,4,5,4).pipe(
  filterFours
).subscribe(console.log);

this is semantically the same:

of(1,4,2,4,3,4,5,4).pipe(
  filter(v => v != 4)
).subscribe(console.log);

So the thing that filter(v => v != 4) returns is the same kind of thing that filterFours is. They do the same thing.

Upvotes: 1

Adrian Brand
Adrian Brand

Reputation: 21638

handleError is a function that returns a function. That function is what is passed into the catchError. It is the same as

catchError((err: any, caught: Observable<any>): Observable<string> => {
  console.log('error is ', err);
  return of('I', 'II') ;
})

as that is the function handleError returns.

Upvotes: 1

Related Questions