'Filter undefined from RxJS Observable
Is there a specific idiom or utility used to filter undefined
from RxJS observables? This code has the behavior I want:
obs.pipe(filter(x => x !== undefined))
Some alternatives are
obs.pipe(filter(x => x)) // for all falsy values
obs.pipe(filter(Boolean)) // for falsy variables using Boolean ctor
Solution 1:[1]
Strictly speaking, using filter alone to remove undefined values doesn't do everything that you need. It filters out the undefined values, but does not change the type to indicate that undefined is no longer a possible value.
In the example:
const obs = new Subject<string | undefined>;
const stringObs = obs.pipe(filter(x => x !== undefined))
the stringObs
observable still has the type Observable<string | undefined>
.
To get round this problem, you need to use:
const stringObs = obs.pipe(filter(x => x !== undefined) as OperatorFunction<string | undefined, string>)
This is only really an issue if you use strict null checks, but if you do (and arguably you should) then creating a custom operator suddenly makes a lot more sense! Something like
function filterNullish<T>(): UnaryFunction<Observable<T | null | undefined>, Observable<T>> {
return pipe(
filter(x => x != null) as OperatorFunction<T | null | undefined, T>
);
}
does the job.
You can then use:
const stringObs = obs.pipe(filterNullish())
and the type of stringObs
will be Observable<string>
. I was quite impressed that Typescript manages to infer the type of T
correctly.
Solution 2:[2]
To help typescript understand that undefined values have been removed, one way is to create a custom operator. Another way is possible via a user-defined type guard.
function isDefined<T>(arg: T | null | undefined): arg is T extends null | undefined ? never : T {
return arg !== null && arg !== undefined;
}
const obs = from(['hello', null, undefined]);
const filtered: Observable<string> = obs.pipe(filter(isDefined));
Solution 3:[3]
Rxjs operators are considered low-level and are intended to be combined in a readable way to create a resultant observable that you can use predictably. Having a 'utility' do that for you isn't exactly what I would (humbly) call "the rxjs way". If by 'idiom' you mean like a convention, your code example is basically what you're looking for.
I myself use that exact filter pattern on a regular basis, to the point where I've considered making a custom operator; however, rather than this:
obs.pipe(filter(x => x !== undefined))
You'll just end up with this:
obs.pipe(notUndefined()) // or hasValue() or whatever you want to name it...
There are not a lot of savings here. I would argue that you're not even getting savings in readability (or a totally marginal one, at that), which is why I've never gotten around to it. Another justification for not mobilizing on that is that it is also common to filter against a boolean value, which then starts to make you wonder if you should combine the two to avoid having too many confusing/like operators, all of which could be easily created using filter
anyways, etc etc...
Long story short, I've thought about this exact issue a lot, and would argue that you simply use the code example you provided. It's "correct". It's "rx-js-y". It's readable.
Solution 4:[4]
I think i'm right in saying you can just use:
obs.pipe(filter(x => x))
which is equal too:
obs.pipe(filter(x => x !== null && x !== undefined))
Solution 5:[5]
As the latest version of the typescript expects a predicate of boolean, it is not supporting previous falsy filters like:
filter(x => x)
in that case you might want to use:
filter(x => !!x)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Simon Williams |
Solution 2 | |
Solution 3 | dudewad |
Solution 4 | Chris |
Solution 5 | Syed Mohammad Fahim Abrar |