Explore the intricacies of RxJS catchError

I am a beginner in RxJS and I am struggling to understand how the parameters are passed in this code snippet:

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

The output produced by this code is:

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

Upon inspection of the catchError function, it reveals:

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

My inquiries are as follows:

  1. How does the handleError function receive the err and caught values from the catchError function without them being explicitly passed?
  2. Why are the err and caught values accessible only within the return function of handleError?
  3. Is there a distinction between the Type of the observable and the ObservableInput being passed as parameters?
  4. What exactly does the OperatorFunction returned by catchError do? Ultimately, it returns an observable with values I and II.

Answer №1

One may wonder: how does the handleError function manage to retrieve the err and caught values from the catchError function without any explicit passing of parameters?

Although there is no direct connection between the catchError function and the "err and caught value," there exists a static relationship. The key lies in returning a function of the correct type.

To elaborate further, one could draw parallels to Haskell Curry's perspective where the arguments are handled separately by handleError through partial application. The full application process transpires within the catchError function as shown below:

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

In this scenario, curry_add requires three applications before yielding a result, akin to how catchError interacts with handleError.

  1. Why do the err and caught values only become accessible within the return function of handleError?

Once again, the concept of partial application comes into play, viewing them as the second stage of applying the handleError function. This allocation of values is facilitated by the catchError operator, which handles the secondary application behind the scenes.

  1. Is it possible that two types are being transferred - one representing the Type of the observable, and the other indicating the ObservableInput?

The entities passed include both the error instance and the observable responsible for triggering the error.

  1. How can one comprehend the operator function returned from catchError? Eventually, an observable containing values I and II is returned.

An OperatorFunction modifies an observable, with various operators like map, tap, switchMap, catchError generating distinct instances of OperatorFunctions. By adhering to this pattern, one can create custom OperatorFunctions independently if needed.

For example, consider the following custom filter implementation:

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 custom filter function operates equivalently to the standard approach using 'filter':

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

Hence, both filter(v => v != 4) and filterFours serve the same purpose, showcasing the versatility of creating custom OperatorFunctions.

Answer №2

When using the handleError function, it will return a specific function that is then passed into the catchError method. The returned function is structured similarly to:

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

This returned function is exactly what the handleError function provides.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The parameter failed to initialize causing the HTTP service to fire prematurely

In my project, I am utilizing Angular 10. Within the ngOnInit function, I have nested HTTP calls structured like this: ngOnInit(): void { let communetyid; this.route.data.subscribe(data => { this.route.params.subscribe(params => { ...

I'm puzzled as to why my createDoorMethod is returning a string value instead of a number, even though I am passing it a number. Can someone help me

Currently enrolled in a web development course, I am diving into the world of Angular 2 and TypeScript. Despite following along with the video tutorial and using the same code, my implementation is not working as expected, leaving me puzzled. Here is the ...

AngularJS - Unusual outcomes observed while utilizing $watch on a variable from an external AngularJS service

Within the constructor of my controllers, I execute the following function: constructor(private $scope, private $log : ng.ILogService, private lobbyStorage, private socketService) { this.init(); } private init(){ this.lobbyData = []; this.initial ...

Tips for retrieving the most recent number dynamically in a separate component without needing to refresh the page

Utilizing both the Helloworld and New components, we aim to store a value in localStorage using the former and display it using the latter. Despite attempts to retrieve this data via computed properties, the need for manual refreshing persists. To explore ...

The specified '<<custom component name>>' argument does not match the 'Type<<custom component name>>' parameter

I'm currently facing an error that indicates a type parameters mismatch, but I can't pinpoint where in the process it's happening. Argument of type 'ModalUserInfoComponent' is not assignable to parameter of type 'Type<Mo ...

The problem with the Custom Select Component: Error Arises When Utilizing the Generic Type <T,> with a Comma as Opposed to <T> Without a Comma

I recently developed a unique custom select component that extends the standard HTML select element. During the process, I made use of a generic type to accommodate a wide range of data types, but encountered an unexpected error. The issue seems to persist ...

Tips on assigning array union as the return type of a function

I am working with a function parameter that accepts an array union, like this: (ClassA|ClassB)[]. How can I return either ClassA[] or ClassB[] from the function? When attempting to return type (ClassA|ClassB)[], I encounter the following error: Assig ...

Elementary component placed in a single line

Creating a text dropdown menu using the following code: import { Autocomplete, TextField } from '@mui/material' import React, { useState } from 'react' const options = [ 'Never', 'Every Minute', 'Every 2 ...

Ways to modify Angular pipe without specifying data types

I am in the process of extracting an Angular pipe from an application to a library. The current pipe is tied to specific types, but I want to change it to use generic types while maintaining type safety. Original Pipe: import { Pipe, PipeTransform } fr ...

Tips for incorporating momentjs into TypeScript within AngularJS 1.5

I am looking to integrate the momentJs library into my TypeScript code for Date object operations. However, I need some guidance on how to inject TypeScript in AngularJS, as it differs slightly from JavaScript. angular.module("app") .config(functio ...

Typescript implementation for a website featuring a single overarching file alongside separate files for each individual webpage

Although I've never ventured into the realm of Typescript before, I am intrigued by its concept of "stricter JS". My knowledge on the subject is currently very limited as I am just starting to experiment with it. Essentially, I have developed my own ...

The specified class is not found in the type 'ILineOptions' for fabricjs

Attempting to incorporate the solution provided in this answer for typescript, , regarding creating a Line. The code snippet from the answer includes the following options: var line = new fabric.Line(points, { strokeWidth: 2, fill: '#999999', ...

"An error occurred: Uncaught SyntaxError - The import statement can only be used within a module. Including a TypeScript file into a

I need to integrate an Angular 10 TypeScript service into a jQuery file, but I am facing an issue. When I try to import the TypeScript service file into my jQuery file, I encounter the following error: Uncaught SyntaxError: Cannot use import statement outs ...

What is a more efficient way to differentiate a group of interfaces using an object map instead of using a switch statement?

As someone still getting the hang of advanced typescript concepts, I appreciate your patience. In my various projects, I utilize objects to organize react components based on a shared prop (e.g _type). My goal is to automatically determine the correct com ...

Combining files/namespaces/modules in Typescript: How to do it?

Even though I believe the solution may be simple, understanding how to merge enums across multiple files is eluding me when reading through the documentation. // a.ts enum Color{ RED, BLUE } // b.ts enum Day{ MONDAY, TUESDAY } // c ...

options argument containing a keyof this

When defining a method type signature, it is possible to use keyof this to restrict an argument to the string name of a valid key of the class. However, using this approach does not work when the method accepts options-style arguments instead of positional ...

Switch button - reveal/conceal details

I am looking for assistance in toggling the visibility of information when clicking on an arrow icon. I have attempted to use JavaScript, but it was unsuccessful. My goal is to hide the information below by clicking on the downward-facing arrow image , an ...

What causes the Angular child component (navbar) to no longer refresh the view after a route change?

Hello everyone, I'm excited to ask my first question here. Currently, I am working on developing a social network using the MEAN stack and socket.io. One of the challenges I am facing is displaying the number of unread notifications and messages next ...

Developing Your Own Local Variable in Angular with Custom Structural Directive ngForIn

I am hoping for a clear understanding of this situation. To address the issue, I developed a custom ngForIn directive to extract the keys from an object. It functions correctly with the code provided below: import {Directive, Input, OnChanges, SimpleChan ...

Instantiate the component array upon object instantiation

I'm currently in the process of learning Angular 2, so please bear with me if this question seems trivial. I am attempting to create a dynamic form that can be bound to a model. However, I am encountering an issue where I am unable to initialize my ar ...