How to combine 2 combineLatest to bypass the 6 arguments limitation

Viewed 964

The maximum amount of arguments that combineLatest can take as input is 6.

More specifically, it takes as input one array that can have up to 6 elements. This way types are automatically inferred.

So if in the below code I add this.someMethodReturningObservable7() I break it:

someMethod(...) {
  return combineLatest([
    this.someMethodReturningObservable1(),
    this.someMethodReturningObservable2(),
    this.someMethodReturningObservable3(),
    this.someMethodReturningObservable4(),
    this.someMethodReturningObservable5(),
    this.someMethodReturningObservable6(),
    this.someMethodReturningObservable7(), // this causes problems
  ]).pipe(
    map(([arg1, arg2, arg3, arg4, arg5, arg6, arg7]) => ({
      arg1,
      arg2,
      arg3,
      arg4,
      arg5,
      arg6,
      arg7,
    })),
    // do more stuff
  );
}

As long as I keep it to 6 arguments, it works fine. With more than 6 it doesn't.

How can I break this down into several combineLatest having maximum 6 arguments each?

2 Answers

You can combine two combineLatests into one like this:

import { of, combineLatest, interval } from "rxjs";
import { map, take } from "rxjs/operators";

const num0$ = of(0 as const);
const num1$ = of(1 as const);
const num2$ = of(2 as const);
const num3$ = of(3 as const);
const num4$ = of(4 as const);
const num5$ = of(5 as const);
const num6$ = of(6 as const);
const num7$ = of(7 as const);
const num8$ = of(8 as const);
const num9$ = interval(1000).pipe(take(3), map(() => 9 as const));

const numsPartOne$ = combineLatest(num0$, num1$, num2$, num3$, num4$);
const numsPartTwo$ = combineLatest(num5$, num6$, num7$, num8$, num9$);

const numCombined$ = combineLatest([numsPartOne$, numsPartTwo$]).pipe(
  // use [[..] [..]] to spread both arrays
  map(([[num0, num1, num2, num3, num4], [num5, num6, num7, num8, num9]]) => {
    // num0 has type 0, etc.
    return {
      num0,
      num1,
      num2,
      num3,
      num4,
      num5,
      num6,
      num7,
      num8,
      num9
    };
  })
);
numCombined$.subscribe(mappedNums => console.log(mappedNums));

Well basically you need to split array in chunks by 6 elements apply combineLates per chunk and then flat the result array. Example:

  /**
   * Overcoming limitation on 6 observables in the combineLatest
   */
  private combineMoreLatest(args: Array<Observable<unknown>>): Observable<unknown> {
    const limit = 6;
    const length = parseInt((args.length / limit) + '') + 1;
    return combineLatest(
      Array.from({ length })
        .map((_, i)=> args.slice(i * limit, (i + 1) * limit))
        .map(arr => combineLatest(arr))
      )
      .pipe(map(combined => combined.flat()))
  }

Now you can call this method instead of the combineLatest, and it accepts up to 36 observables :)

Related