Rxjs Observable gets <unknown> type assigned when to many taps piped. Why is that?

Viewed 55

I noticed that if i pipe many taps an observable gets unknown type assigned. Why is that?

Here is a stackblitz example. If you comment/uncomment a tap you will see the test$ observable being assigned an unknown type.

import { of, Observable, combineLatest, BehaviorSubject } from 'rxjs';
import { filter, map, shareReplay, switchMap, tap } from 'rxjs/operators';

interface Test {
  key1: string;
}

const _selectedId = new BehaviorSubject<string>(null);

const test$: Observable<Test[]> = combineLatest([_selectedId]).pipe(
  filter(([id]) => !!id),
  switchMap(([id]) => httpCall()),
  tap((test) => console.log(test)), //ADD OR REMOVE A TAP TO TRIGGER TYPE ERROR
  tap((test) => console.log(test)),
  tap((test) => console.log(test)),
  tap((test) => console.log(test)),
  tap((test) => console.log(test)),
  tap((test) => console.log(test)),
  tap((test) => console.log(test)),
  shareReplay(1)
);

const httpCall = (): Observable<Test[]> => {
  return of([{ key1: 'testing1' }]);
};

_selectedId.next('test');

test$.subscribe((data) => {
  console.log(data);
});
1 Answers

Look at how pipe is defined in Observable.ts :

pipe(): Observable<T>;
pipe<A>(op1: OperatorFunction<T, A>): Observable<A>;
pipe<A, B>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>): Observable<B>;
pipe<A, B, C>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>): Observable<C>;
pipe<A, B, C, D>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>): Observable<D>;
pipe<A, B, C, D, E>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>): Observable<E>;
pipe<A, B, C, D, E, F>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>): Observable<F>;
pipe<A, B, C, D, E, F, G>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>, op7: OperatorFunction<F, G>): Observable<G>;
pipe<A, B, C, D, E, F, G, H>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>, op7: OperatorFunction<F, G>, op8: OperatorFunction<G, H>): Observable<H>;
pipe<A, B, C, D, E, F, G, H, I>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>, op7: OperatorFunction<F, G>, op8: OperatorFunction<G, H>, op9: OperatorFunction<H, I>): Observable<I>;
pipe<A, B, C, D, E, F, G, H, I>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>, op7: OperatorFunction<F, G>, op8: OperatorFunction<G, H>, op9: OperatorFunction<H, I>, ...operations: OperatorFunction<any, any>[]): Observable<unknown>;

As you can see the last definition

pipe<A, B, C, D, E, F, G, H, I>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>, op7: OperatorFunction<F, G>, op8: OperatorFunction<G, H>, op9: OperatorFunction<H, I>, ...operations: OperatorFunction<any, any>[]): Observable<unknown>;

There is a spread operator ...operations: OperatorFunction<any, any>[] which will allow to have as any parameters you want and will return Observable<unknown>.

So the pipe method support up to 9 operator functions with the right return type and after it will just return unknown if you add one more !

Related