RxJS Mastery – #65 materialize & dematerialize

RxJS materialize and dematerialize operators

The RxJS materialize and dematerialize operators are utility operators. Probably you have not used them anywhere in your code yet. But for sure you have come across them indirectly, e.g., through testing output.

RxJS materialize wraps all notifications

The materialize operator transforms all notifications to next notifications and tags them with the original type. This means that a complete notification is wrapped with a Notification object of kind 'C' while normal next notifications end up with kind 'N' as seen below:

const source$ = cold('ab|').pipe(
    materialize(),
);

expectObservable(source$).toBe(
    'ab(c|)', {
        a: new Notification('N', 'a'),
        b: new Notification('N', 'b'),
        c: new Notification('C'),
    }
);

Please note that the stream itself completes. That is why there is a '|' denoting completion specified in the expected Observable.

RxJS materialize with error notification

Also, error notifications can be transformed and show up with the occurred error in the Notification object.

const source$ = cold('ab#').pipe(
    materialize(),
);

expectObservable(source$).toBe(
    'ab(c|)', {
        a: new Notification('N', 'a'),
        b: new Notification('N', 'b'),
        c: new Notification('E', undefined, 'error'),
    }
);

One can say that materialize annotates notifications with metadata.

The RxJS dematerialize goes in the other direction

The dematerialize operator reverses the effect of materialize. Hence, if the former operator is applied after the latter, the final emission is the original one:

const source$ = cold('ab|').pipe(
    materialize(),
    dematerialize(),
);

expectObservable(source$).toBe(
    'ab|'
);

This post is part of the RxJS mastery series. As always the code examples can be found on GitHub.