I'm currently working on developing an RxJS operator that waits for the input operator to complete before switching to a second operator generated dynamically using switchMap. I have created two versions of the code, one that works perfectly and another that doesn't seem to function as expected. I am struggling to understand why there is a discrepancy between the two implementations.
The successful version is as follows:
import { Observable } from "rxjs"; // OperatorFunction,
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";
// This definition of OperatorFunction is more or less equivalent to the
// definition in rxjs/src/internal/types.ts
interface OperatorFunction<T, S> {
(input: Observable<T>): Observable<S>;
}
interface ObservableGenerator<T, S> {
(value: T): Observable<S>;
}
export function switchMapComplete<T, S>(project: ObservableGenerator<T, S>): OperatorFunction<T, S> {
function mapper(obs1: Observable<T>): Observable<S> {
return obs1.pipe(
defaultIfEmpty(null),
last(),
switchMap(project)
);
}
return mapper;
}
The non-functional version, with changes only in the definitions of OperatorFunction
and OperatorGenerator
, looks like this:
import { Observable } from "rxjs";
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";
type OperatorFunction2<T, S> = <T, S>(obs: Observable<T>) => Observable<S>;
type ObservableGenerator2<T, S> = <T, S>(value: T) => Observable<S>;
export function switchMapComplete2<T, S>(project: ObservableGenerator2<T, S>): OperatorFunction2<T, S> {
function mapper(obs1: Observable<T>): Observable<S> {
return obs1.pipe(
defaultIfEmpty(null),
last(),
switchMap(project)
);
}
return mapper;
}
The latter version results in a compiler error displaying the following exception:
error TS2322: Type 'Observable<{}>' is not assignable to type 'Observable<S>'.
Type '{}' is not assignable to type 'S'.
util.ts(49,5): error TS2322: Type '(obs1: Observable<T>) => Observable<S>' is not assignable to type 'OperatorFunction2<T, S>'.
Types of parameters 'obs1' and 'obs' are incompatible.
Type 'Observable<T>' is not assignable to type 'Observable<T>'. Two different types with this name exist, but they are unrelated.
Type 'T' is not assignable to type 'T'. Two different types with this name exist, but they are unrelated.
This result was unexpected, and despite referring to the TypeScript documentation which states that both versions should be equivalent, I encountered this issue.
If anyone can provide insights into why the equivalence between the two versions breaks down in this scenario, I would greatly appreciate it.
PS: If you require an RxJS operator similar to mine, here is an alternative solution which is simpler and leverages the existing types provided by RxJS:
import { Observable, ObservableInput, OperatorFunction, pipe } from "rxjs";
import { defaultIfEmpty, last, switchMap } from "rxjs/operators";
export function switchMapComplete<T, S>(project: (value: T) => ObservableInput<S>): OperatorFunction<T, S> {
return pipe(
defaultIfEmpty(null),
last(),
switchMap(project)
);
}