Engineering
March 2, 2023
Typescript-friendly label fallbacks

I'm not sure exactly what to call this fairly common pattern, but there are a bunch of strings in Buttondown that I want to be able to pretty-print in a fallback-friendly way.

UTM campaigns are a great example: 95% of the time this value is facebook or twitter or blog or email but it technically can be anything. So you round up the most common keys and throw them in a map that you can reference down the line:

const UTM_CAMPAIGN_TO_LABEL = {
    'facebook': "Facebook",
    'reddit': "Reddit",
    'linkedin': "LinkedIn"
    // ... and so on
};

[
    "facebook",
    "reddit",
    "linkedin",
    "yandex"
].map(campaign => UTM_CAMPAIGN_TO_LABEL[campaign] || campaign)

The problem is that, by default, Typescript doesn't like that — it knows what's in your map, and unless the strings you pass in are a strict subset of those keys it's sad.

All you need to do is ease the type inference by expanding the key type to string, like so:

const UTM_CAMPAIGN_TO_LABEL: {[key in string]: string} = {
    'facebook': "Facebook",
    'reddit': "Reddit",
    'linkedin': "LinkedIn"
    // ... and so on
};

[
	"facebook",
	"reddit",
	"linkedin",
	"yandex"
].map(campaign => UTM_CAMPAIGN_TO_LABEL[campaign] || campaign)

This is trivial, and despite its triviality I forget how to do this around 40% of time. My hope is that you, too, may discover this if you google "typescript-friendly label fallbacks" (because what else are you going to call this pattern? I honestly have no idea.)

Sign up for the greatest newsletter in the world.
Email not your thing? Well, that's a whammy. Twitter or RSS, I guess?
Buttondown is the easiest way to start a newsletter.
Get started today: