'Filter all 'null' values from an Observable<T>

I have a service with a subject:

@Injectable() export class UserService() {
    private currentUserSubject = new BehaviorSubject<User>(null);
    public currentUser = this.currentUserSubject.asObservable().distinctUntilChanged(); 

    ... // emitting new User    
}

Have a component I inject this service into and subscribing on updates:

@Component() export class UserComponent {
    constructor(private userService: UserService) {
        this.userService.currentUser
            .subscribe((user) => {
                // I want to see not null value here
            })
    }
}

I want to apply something to Observable<User> to filter all null values and get into subscribe only when User is actually loaded.



Solution 1:[1]

Another way to check the value exists:

public currentUser = this.currentUserSubject
                         .asObservable()
                         .filter<User>(Boolean)
                         .distinctUntilChanged(); 

Solution 2:[2]

with rxjs@6 and typescript the recommended (readable/maintainable) way is to define the following type guard:

export function isNonNull<T>(value: T): value is NonNullable<T> {
  return value != null;
}

and augment a subject with pipe and filter:

subject.pipe(filter(isNonNull))

Solution 3:[3]

It's as simple as:

filter(user => !!user),

So would filter these falsy values (link to Falsy on MDN). or alternatively cast to a boolean like this:

filter(user => Boolean(user)),

If user evaluates to false, the filter will not be passed.


Update (after Mick his comment on type checking):

If you want to add some more proper typescript solution you could use a type predicate (user-defined type guard). See documentation on this here on https://www.typescriptlang.org/ .

Assume you have a class User. Example:

const isUser = (user: null|User): user is User => {
  // Using an instance of check here, which is not the most performant
  // but semantically most correct.
  // But you could do an alternative check and return a boolean instead
  return user instanceof User;
}

If you now do:

filter(user => isUser(user));

Typescript will understand that you have an object of type User after the filter.

Solution 4:[4]

Another option for rxjs@6 is to create another wrapping operator of skipWhile.

// rxjs.utils.js
export const skipNull = () => <T>(source: Observable <T>): Observable<T> => source.pipe(skipWhile(value => value === null));

Usage:

this.observable.pipe(skipNull()).subscribe(...)

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 jenson-button-event
Solution 2 Amit Portnoy
Solution 3
Solution 4 noamyg