RxJS - fix type of combineLatest result

Viewed 283

I come across this often in Angular when I work with combineLatest to combine 2 observables that emit optional values.

The basic pattern is this:

const ob1: Observable<Transaction[] | null>;
const ob2: Observable<Price[] | null>;

const currentValue = combineLatest([ob1, ob2]).pipe(
  filter(([a, b]) => !!a && !!b),
  map(([a, b]) => {
    // Here the type of both and a and b is nullable
    const x = a.map(a => a.id); // This gives compilation error that a can be null
  });

I want to do work in the map function to combine the events once both observables emit non null values.

The filter does indeed filter but the type of each element is still T | null.

I want the type to be Transaction[] for a and Price[] for b without using a! or b!.

This pattern repeats a lot in my code and I would like to find a solution that is short and elegant and does not require me to write boiler plate code for each use case.

I found some answers how to fix this for a single value. But how do I do this for a tuple or array?

2 Answers

How about simple casting? Add another map to pipe after filter: map(([a,b])=> [a,b] as [Transaction[], Price[]]), or even cast it inside your map body.

Creating two types of your required tupple will help you to solve your problem.

        function filterNullish<T, K>(): UnaryFunction<Observable<[T |null, K | null]>, Observable<[T, K]>> {
          return pipe(
             filter(([a, b]: [T |null, K | null]) => !!a && !!b) as 
             OperatorFunction<[T |null, K | null], [T, K]>
    );
}

        const currentValue = combineLatest([ob1, ob2]).pipe(
            filterNullish() ,
            map(([a, b]) => {
                const x = a.map(a => a);
                const y = b;
                return x;
            })).subscribe((r) => console.log(r));
Related