Extracting a custom RxJS operator

extracting a custom RxJS operator from an observable pipe chain.

Using multiple pipe operators on an Observable to do one thing can make it harder to understand. This is the same problem as in "normal" code.

With normal code we extract a method if the steps involved don’t fit the abstraction level of the code we are working on. We can do the same with an Observable by extracting the steps into a custom rxjs operator.

Lets say we have an article$ observable: Observable<Article[]>. It provides a list of all blog articles unordered and with a mix of published and unpublished articles.

We want to find the latest published article. That could look like this:

articles$
.pipe(
    map (articles => {
      return articles
        .filter (r => r.published)
        .sort((l, r) => r.date.localeCompare (l.date))
        .shift()
    })
)
.subscribe(...);

If we want to use the latest published article we don’t care so much about the details to get it. The code would be easier to read if it would just say:

articles$
  .pipe(
    latest()
  )
  .subscribe(...);

It is possible with a custom rxjs operator.

The function returns a factory function that takes the source observable as parameter and returns it modified by the pipe operator chain we used in the initial code:

export function latest (): OperatorFunction<Article[], Article> {
  return (source$: Observable<Article[]>) => {
    return source$
      .pipe(
        map (routes => {
          return routes
            .filter (r => r.published)
            .sort((l, r) => r.date.localeCompare (l.date)
            .shift()
        })
      )
  };
}

It is also easier to write marble tests for this.

That’s it.