Adding custom operators to RxJS
RxJS is already shipping with a lot of operators which mostly fulfill all requirements you might have, but perhaps you are missing something. Or if you want to treat a bunch of observables the same way with a specific combination of operators it’s not useful to manually write and maintain them everywhere all separately. To address this issue you can easily add your custom operators to an RxJS.Observable.
Lets start with a simple example. We want to use the filter operator on more than one observable. However we want to use the same condition everywhere in our code. Changes to that specific filter condition should apply to all observables at once. (Don’t Repeat Yourself principle)
So lets add our custom filter operator to the prototype of the observable. You just can do this through adding these few lines of code:
1 2 3 |
Observable.prototype.filterUndefined = function (): Observable<any> { return this.filter((value: any) => !!value); }; |
As we really like using typscript in combination with IntelliJ as our IDE we would expect explicit typing and also code completion when working with an observable. But our own operator is not known to IntelliJ and therefore there is no suggestion while writing the name of our operator.
This might be quite irritating the next time you want to use this operator or if you are working in a team the others will not use this operator without knowing it, we should do something to make IntelliJ recognize this operator. So lets tell IntelliJ that this operator exists through “adding” a typescript module declaration in our code. Just add these code snippet somewhere in the code.
1 2 3 4 5 |
declare module "rxjs/Observable" { interface Observable<T> { filterUndefined: () => Observable<T>; } } |
You might know there is already a module with the same name we are referencing delivered by the RxJS library. The nice thing about the typescript module system is, that you can extend existing module definitions by augmenting them. For details on declaration merging we highly recommend the Typescript handbook.
As a result, IntelliJ now knows that there is an operator called filterUndefined available on the observable.
This was just an easy example of adding a custom operator, but you can also do more complex things, like reacting differently dependent on the result of the observable. For example look at the following code which is using the default do operator to perform console logging depending on the kind of event.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Observable.prototype.logger = function (): Observable<any> { return this.do( function (value: any): void { console.log("Value:", value); }, function (err: any): void { console.error("Error:", err); }, function (): void { console.log("Complete"); } ); }; |
As we haven’t mentioned yet where to add the module augmentation and declarations, we just want you to think of this as a kind of polyfill for all browsers. So a good place is to add this near where you are adding polyfills to your code.
If you want to read more about prototype we recommend you the chapter prototypes from the book You Don’t Know JS: this & Object Prototypes.
It is also possible instead of extending the prototype to write an Observable subclass or use the new ES7 bind feature, see also RxJS documentation.
Recent posts






Comment article