Union Types and Literal Types

This or that, but nothing else

9 min read

Sometimes a value can be one of a few things

Not every value fits neatly into a single type. An ID from an old database might be a number, while new IDs are strings. A union type says a value may be one of several types, written with a vertical bar:

let orderId: string | number;

orderId = 'A-1043';
orderId = 1043;
orderId = true;

The first two assignments are fine. The third is an error, because boolean is not part of the union. Read string | number as string or number.

Narrowing: helping TypeScript zoom in

When a value could be either type, TypeScript only lets you do things that are safe for both. To use string-only or number-only features, check which one you actually have. This is called narrowing:

function describeId(id: string | number): string {
  if (typeof id === 'string') {
    return id.toUpperCase();
  }
  return 'Order #' + id.toFixed(0);
}

Inside the if, TypeScript knows id is a string, so toUpperCase is allowed. After it, only number remains, so toFixed is allowed. Plain JavaScript typeof checks are all it takes.

Literal types: exact values as types

Here is where unions get really lovely. A type can be a specific value, not just a broad category. Combine a few literal values into a union and you get a type that only accepts an exact list of options:

type Size = 'small' | 'medium' | 'large';

let drink: Size;
drink = 'medium';
drink = 'venti';

Assigning 'venti' is an error, because it is not one of the three allowed strings. Compare that with plain string, which would accept any text at all, including typos like 'mediun'. Literal unions turn a whole class of spelling bugs into instant red squiggles, and your editor autocompletes the valid options for you.

The type keyword

That example used type to create a named alias, the same way interface names an object shape. A type alias can name any type, including unions, which is why the two keywords live side by side in most projects: interfaces for object shapes, type aliases for unions and friends.

Where you will use this: button variants like 'primary' | 'secondary', request states like 'loading' | 'success' | 'error', and sort orders like 'asc' | 'desc'. Small fixed sets of options are everywhere in web code.

Quick check

Q1 A variable is typed as string | number. Which assignment causes an error?

Q2 What is the advantage of type Size = 'small' | 'medium' | 'large' over plain string?

Want to save your progress? It's free.

Create a free account