combineLatest refactoring for @deprecated — resultSelector no longer supported, pipe to map instead?

Viewed 4879

The angular material documentation app has the following snippet in it:

    // Combine params from all of the path into a single object.
    this.params = combineLatest(
      this._route.pathFromRoot.map(route => route.params),
      Object.assign);

TSLint strikesout combineLatest with this message:

@deprecated — resultSelector no longer supported, pipe to map instead

How should that be fixed?

Also if you understand the technique being used, a simple example with elaboration would be awesome.

Here's a code link:

https://github.com/angular/material.angular.io/blob/master/src/app/pages/component-category-list/component-category-list.ts

3 Answers
combineLatest(observables, resultSelector)

can often be replaced with

combineLatest(observables).pipe(
  map(resultSelector)
)

But whether this works in the same way depends on what parameters your resultSelector accepts. combineLatest(observables) emits an array and RxJs automatically spreads this array when you're using the deprecated resultSelector.

return isArray(args) ? fn(...args) : fn(args); // fn is your resultSelector

As Object.assign returns different values depending on whether you provide an array or multiple values you have to spread the array manually.

combineLatest(observables).pipe(
  map(items => Object.assign({}, ...items))
)

The result selector is just a function that can be used to change the shape of the output.

So, you can simply omit the result selector param and use a map to transform the shape:

    this.params = combineLatest(
      this._route.pathFromRoot.map(route => route.params)
    ).pipe(
        map(Object.assign)
    );

A common use the of the result selector (for me anyway) was to return the array as an object with named properties, so something like this:

// Old Way

myObs$ = combineLatest(
   [src1$, src2$, src3$], 
   ([src1, src2, src3]) => ({src1, src2, src3})
);

// New Way

myObs$ = combineLatest(src1$, src2$, src3$)
    .pipe(
       map(([src1, src2, src3]) => ({src1, src2, src3}))
    );

pipe the result and use the map operator instead, something like:

combineLatest(this._route.pathFromRoot.map(route => route.params)).pipe(
  map(Object.assign)
);

Reference

Also, not sure about the intent of the code, since it seems as though it's calling Object.assign on a new array reference, not sure why that's necessary, but that's not entirely relevant.

Related