Image for post
Image for post
Photo by Markus Spiske on Unsplash

Recently, I noticed a Twitter thread from Rob Palmer in which he described some performance problems that were caused by the use of type alias declarations in TypeScript.

Specifically, the use of a type alias declaration effected a much larger .d.ts output:

Yesterday I shrank a TypeScript declaration from 700KB to 7KB by changing one line of code 🔥

In the thread, Rob points out that the reason this happens is because type alias declarations can be inlined, whereas interfaces are always referenced by name.

Let’s have a look at some code that demonstrates this inlining behaviour.

Here’s a TypeScript playground snippet in which a type alias is used to declare the callback…

Image for post
Image for post
Photo by Annie Spratt on Unsplash

When solving a problem that involved a frozen object, I learnt a bit more about the details of JavaScript object property access and some of those details are kinda interesting.

The Problem

Recently, I replaced an ESLint rule that was specific to arrays — no-array-foreach — with a more general rule — no-foreach — that also effected failures for the Set, Map and NodeList types.

The no-foreach rule supports a types option — so the that the types for which it is enforced can be configured by the developer — and I planned to leverage that by deprecating and re-implementing no-array-foreach to use no-foreach internally. …

Image for post
Image for post
Photo by Erwan Hesry on Unsplash

RxJS — and Rx in general — offers a bunch of guarantees that make it possible to compose observable chains. Specifically, it’s guaranteed that:

  • observers won’t receive notifications after an error or complete notification; and
  • observers won’t receive notifications after explicitly unsubscribing.

There is more information about this in the Observable Contract.

The guarantees allow for the declarative composition of observable chains: developers can focus on composing behaviours rather than keeping track of state. Without the guarantees, developers would be checking for errored or completed sources and composition would be more difficult.

A quirk that stems from these guarantees is that it’s possible for an error channel to be closed. For example, if an error occurs when an observable is being torn down, it’s not possible for that error to be reported to the observer — the observer will have already received a complete or error notification or will have already been explicitly unsubscribed. In RxJS, observers in this state are referred to (internally) as stopped. …

Image for post
Image for post
Photo by Matt Artz on Unsplash

I thought I’d write up a short post to explain a TypeScript problem that took up far too much of my time.

The TL;DR is that if you have overload signatures for a function that takes a variable number of (initial) arguments, the ordering of the signatures matters in a way that is not obvious. And the ‘simplest’ signature should be placed first.

The types I was working with were in RxJS, but to keep things general let’s use an example that combines a bunch of arrays in some way, like this:

Image for post
Image for post
Photo by Beatriz Pérez Moya on Unsplash

The publish and publishReplay operators can be called in two ways: either with or without a selector function. Let’s look at the differences and at why you should almost always pass a selector.

Without a selector

When publish is called without a selector, it returns a particular type of observable: a ConnectableObservable.

A ConnectableObservable is a little unusual. It does not connect — i.e. subscribe — to its source when a subscriber subscribes. Instead, a ConnectableObservable subscribes to its source when its connect method is called.

This behaviour can be used to control the order in which subscriptions occur and to compose observables before a subscription is made to the source. …

Image for post
Image for post
Photo by Corinne Kutz on Unsplash

A while ago, I wrote a linting rule to highlight an error that I’d made on a few occasions. Let’s look at the error — and its variations — and then at the rule that prevents it.

The error

If you are used to working with fluent APIs — perhaps with D3 or lodash — it feels natural to write Array-based code like this:

const developers = employees
.filter(e => e.role === "developer")
.map(e =>

Which is fine. There’s no error in that code.

However, in situations in which you don’t need to filter or map, you might write something like…

Image for post
Image for post
Photo by Monika Stawowy on Unsplash

Introducing unintentional dependencies on rxjs-compat is something that I see developers doing every now and then. Let’s have a look at rxjs-compat to see what it is, how it works and how depending upon it can be avoided.

If you’re only interested in avoiding the dependency, skip to the TL;DR at the bottom of the article.

So what is it?

In RxJS version 6, breaking changes made the library simpler:

  • the prototype-patching operators were removed; and
  • the export locations were rearranged so that each export was available from only a single location.

Those changes made the library easier to maintain, document and explain, but they created a burden for developers with large RxJS-version-5 codebases: pretty much all RxJS-related code would need to be modified. …

Image for post
Image for post
Photo by Namroud Gorguis on Unsplash

In RxJS version 6.4.0, a change was made to the shareReplay operator. Let’s look at why the operator needed to be changed, what was changed and how the change can be used to avoid surprises — and bugs.

If you’re only interested in the change, skip to the TL;DR at the bottom of the article.

The operator’s history

The shareReplay operator was introduced in version 5.4.0.

Like the share operator, shareReplay returns a hot, reference-counted observable, but replays the specified number of next notifications. …

Image for post
Image for post
Photo by Victoire Joncheray on Unsplash

When pipeable operators were introduced in RxJS version 5.5, writing user-land operators became much simpler.

A pipeable operator is a higher-order function: a function that returns another function. And the function that is returned takes an observable and returns an observable. So, to create an operator, you don’t have to subclass Operator and Subscriber. You just write a function.


However, there are situations in which you need to take some extra care. In particular, you need to be careful whenever your operator stores internal state.

An example

Let’s look at an example: a debug operator that logs received values and their indices to the console. …

Image for post
Image for post
Photo by pan xiaozhen on Unsplash

I often see code that looks a little like this:

Which seems fine.

Well, it is fine — as long as the extractSomeProperty and handleError methods do not depend upon the this context in their implementations.

Why might this be a bad thing?

When unbound methods are passed to RxJS, they will be invoked with an unexpected context for this. If the method implementations don’t use this, they will behave as you would expect.

However, there are a number of reasons why, as a general rule, you might want to avoid passing unbound methods:

  • If you are in the habit of passing unbound methods, it’s a near certainty that you will, eventually, introduce a bug by passing, as unbound, a method that uses this in its implementation. Maybe you’ll have a test that picks it up; maybe you won’t. …


Nicholas Jamieson

RxJS core team member; front-end developer; mentor; speaker; open-source contributor

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store