Reputation: 17762
I have 2 Observables. The first one emits numbers
the second emits strings
.
These 2 Observables start emitting when some triggers emit. The triggers are Subjects and each of the 2 Observables has its own trigger.
I want to start a race
between the 2 Observables so that the Observable whose trigger emits first wins and start emitting, while the other is ignored even if its trigger subsequently emits.
This is the code
const observableOfNumber = interval(100).pipe(take(10));
const observableOfNumberFunction = () => observableOfNumber;
const observableOfString = interval(100).pipe(map(number => String.fromCharCode(65 + number)), take(10));
const observableOfStringFunction = () => observableOfString;
const startEmittingNumbers = new Subject<any>()
const emittingNumbers = startEmittingNumbers
.pipe(
map(() => observableOfNumberFunction),
);
const startEmittingChars = new Subject<any>()
const emittingChars = startEmittingChars
.pipe(
map(() => observableOfStringFunction),
);
race(emittingNumbers, emittingChars)
.pipe(
mergeMap(handler => handler())
)
.subscribe(console.log);
This code make Typescript complain with the following error
The code though seems to work fine in its essence.
If I just explicitly declare the return type of observableOfStringFunction
as Observable<any>
, i.e.
const observableOfStringFunction = (): Observable<any> => observableOfString;
Typescript stops complaining and everything works perfectly.
Similarly, if rather than using race
I use merge
, Typescript does not complain even if, from a type-checking point of view, merge
and race
should behave the same.
Can anybody point me to the reason of this different behavior?
Upvotes: 0
Views: 254
Reputation: 8171
This happens because the type that race
returns is the same as the type which emits first from its parameters (ie, the race winner) - Observable<T>
.
In your example the race winner is of type number
because the Type Checker is probably (possibly) evaluating the first arguments' type as the return type as well, and then expects each subsequent emission to be of the same type (which it isn't). If you were to switch your arguments around, you would notice that IntelliSense will give you the same error for your emittingNumbers
param. That is why the IDE complains but the code still runs.
Here is a more explicit example:
const obs1 = interval(1000).pipe(mapTo('fast one')); // Emits first, type string
const obs2 = interval(3000).pipe(mapTo(1)); // Type number, TypeScript will complain
const obs3 = interval(5000).pipe(mapTo('slow one'));
race(obs3, obs1, obs2)
.subscribe(
winner => console.log(winner)
);
const {
Observable,
interval,
Subject,
race
} = rxjs;
const {
map,
take,
mergeMap,
mapTo
} = rxjs.operators;
const obs1 = interval(1000).pipe(mapTo('fast one'));
const obs2 = interval(3000).pipe(mapTo(1)); // TypeScript will complain about this
const obs3 = interval(5000).pipe(mapTo('slow one'));
race(obs3, obs1, obs2)
.subscribe(
winner => console.log(winner)
);
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>
Upvotes: 2