Typescript function signature overloading.


I recently wrote a new library: I often write small atomic and single use libraries when I have to solve a new problem that can be safely isolated. The problem was simple: during a test I needed to be able to wait until a specific DOM element would be spawn, and then do something.

That’s why I wrote Et Voila, that solves the problem with a simple Mutation Observer and looks for the appearance of any DOM element that is recognized by a CSS Selector string. The solution, while easy, could be implemented in two different ways: the first one is to return a Promise that resolves when the element appears (or rejects after an optional timeout); the second one is to require a callback that is fired each time that element appears.

The Problem

There is no specific reason for this, but I really wanted to write and export a single function waitForIt with multiple signatures. I’ve never done it before, so I had to learn how to.

The Syntax

It’s pretty easy, even though it has a little quirk that bugs me (but maybe I just got it wrong):

function isString(foo: string | number): foo is string {
  return typeof foo === 'string'

export function foo(bar: string): string
export function foo(bar: number): [string, number]
export function foo(bar: string | number): string | [string, number] {
  if (isString(bar)) return bar
  return [bar.toString(), bar]

What did I discover

The coolest part is, simply, that this allows me to keep type checking while exporting the same function with multiple signatures.

The strange and uncool part is that I have to manually write a function with a signature that would allow all of the above signatures that my function can support. While strange, this also allows me to write the body in a new, unspecific function without it causing any confusion while reading it.

Also, but that’s less important, one has to prepend export before any signatures.