How to chain switchMap-operators with function bodies in rxjs 6

Martes

I have a mobile app, built with ionic and angular and I want to upgrade that from rxjs 5.5 to rxjs 6. However it appears that there are some breaking changes in the way rxjs uses operators, especially in the way values returned by one switchMap-operator are handled in the next operator in the pipe-chain. This is not clear from the migration docs (https://rxjs-dev.firebaseapp.com/guide/v6/migration), and I cannot find a way to work around it.

The problem might be in my use of function bodies within the switchMap-operators. That approach was based on older Internet-sources, but I see it less in more recent examples, and not sure if it is still supposed to be used.

The reason I need that approach is that the way I use observables is more or less as a replacement for promises - it's a way to make sure that different steps run in sequence. So there is not a single data-stream that runs through the operators, but any operator might be the start of a new type of event. That was a decision made in the past, in order to prevent constant conversions between observables and promises. Looking at it now, it might not be good practice, but for now, I would prefer to leave as is, if possible.

Anyway, take the following as an example:

initializeStatisticsObs(): Observable<any> {
    return this.speciesService.getImagesSizeInBytesObs()
      .pipe(
        switchMap((fSizeInBytes: number) => {
          this.imagesSizeInBytes = fSizeInBytes;
          return this.speciesService.getImagesNumberOfItemsObs();
        }),
        switchMap((fNumberOfItems: number) => {
          this.imagesNumberOfItems = fNumberOfItems;
          return of({});
        }),
..
      )
  }

  getImagesSizeInBytesObs(): Observable<number> {
    return this.speciesLocalStorageService.getSizeInBytesObs();
  }

  getImagesNumberOfItemsObs(): Observable<number> {
    return this.speciesLocalStorageService.getNumberOfItemsObs();
  }

As you can see, the higher level function initializeStatisticsObs() calls two other functions, that both return a number, wrapped in an Observable. Both numbers should ultimately be stored in variables of type number. I know that in this case the whole idea of running asynchronously doesn't really seem to make sense, but it is just a simplified example.

So the call to this.speciesService.getImagesSizeInBytesObs() is called outside a pipe-chain, its output is picked up in the first switchMap, and stored in a variable of type number.

Then a call is made to a second, similar function, this.speciesService.getImagesNumberOfItemsObs(), which again returns a number wrapped in an Observable. This second call should be picked up by the second switchMap operator and again stored in a variable of type number.

This approach worked perfectly well in rxjs 5.5, but I get build-errors in version 6.4.0 or higher. The issue is that apparently the switchMap-operator now adds an additional Observable wrapper, so the second switchMap gets as input a value of type <Observable<number>>, conflicting with the number type of this.imagesNumberOfItems.

The build error I get looks like this:

    Argument of type 'OperatorFunction<number, Observable<{}>>' is not assignable to parameter of type
    'OperatorFunction<Observable<number>, Observable<{}>>'. Type 'number' is not assignable to type
    'Observable<number>'.

The reason why I believe the use of function bodies is the cause of the problem is that when I use this:

 initializeStatisticsObs(): Observable<any> {
    return this.speciesService.getImagesSizeInBytesObs()
      .pipe(
        switchMap((fSizeInBytes: number) => of(23)),
        switchMap((fNumberOfItems: number) => {
          this.imagesNumberOfItems = fNumberOfItems;
          return of({});
        })
 ..
      )
  }

it works fine.

And by the way, the tap() operator can be used with function bodies without these problems, but they aren't suitable for my purposes. Is there a way to resolve this?

Artem Brilev
switchMap((fSizeInBytes: number) => {
      this.imagesSizeInBytes = fSizeInBytes;
      return this.speciesService.getImagesNumberOfItemsObs();
    })

switchMap return Observable and getImagesNumbersOfItemsObs return Observable so your return is Observable>

you should use tap here

tap((fSizeInBytes: number) => this.imagesSizeInBytes = fSizeInBytes)
switchMap(() => this.speciesService.getImagesNumberOfItemsObs())
tap((fNumberOfItems: number) => this.imagesNumberOfItems = fNumberOfItems))

but better to use forkJoin operator here and expected your values as array in subscribe

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Rxjs pipe function with multiple filter() and switchMap() operators in the chain

How to cancel switchmap chain in RxJS?

How to properly chain rxjs 6 observables?

How to use Rxjs switchMap to throwError

How to finilize rxjs switchmap observable?

How to chain Ternary Operators?

RxJS 6 switchMap Deprecated Symbol used

How do I persist a value across RxJS 6 pipe operators?

How to subscribe multiple observable in rxjs 6 ? do is not a function in rxjs 6

How can I chain multiple dependent subscriptions using rxjs operators and transformations?

How to chain rxjs observable

I dont get rxjs 6 with angular 6 with interval, switchMap, and map

How to chain several operators onFailure?

Angular / RXJS - How to perform logic after a switchMap

Could I skip all subsequent operators chain if condition is truthy in RxJS

Missing `switchMap` and `flatMap` overloads containing 'resultSelector' in RxJS6

rxjs6 error handling when using switchMap

Angular6: RxJS switchMap operator is not working as expected

Angular Map and mergeMap rxjs6 operators

How to chain a list of RxJS observable

How to chain requests correctly with RxJS

Why these RxJS operators are not running in my function?

How chain indefinite amount of flatMap operators in Reactor?

Importing RxJS 6 operators into Angular 6 files by default

How to execute switchMap and tap rxJS functions from Jasmine test?

How to handle an observable that may return empty when using switchMap RxJS

RXJS how to handle returned boolean or Observable<boolean> in switchmap

RxJS: SwitchMap for Array of Strings

rxjs switchMap and tap issue