Literal Types and Enums in TypeScript
Literal Types and Enums
~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
BookStatus = 'available' | 'borrowed' | 'reserved' from chapters 8/9 is a union of literal types – this chapter explores that concept further and introduces the ALTERNATIVE to it: enum.
Literal types: more than just strings
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6; // numeric literal types
type YesNo = true | false; // EXACTLY the same as 'boolean'
let roll: DiceRoll = 4; // ✓
roll = 7; // ✗ error - 7 is NOT part of the allowed valuesLiteral types work for ANY primitive type, not just string – numeric literal unions are useful, for instance, for fixed value ranges like dice rolls or rating stars (1-5).
Enums: the classic alternative
enum Genre {
Fantasy,
Mystery,
NonFiction,
Biography,
}
let favoriteGenre: Genre = Genre.Fantasy;
console.log(favoriteGenre); // 0 - enums are NUMERIC by default, starting at 0enum is its OWN language construct (not a pure type like type/interface) – it ALSO exists at runtime as a real JavaScript object, not just at compile time. By default, each value automatically gets a sequential number (0, 1, 2, ...).
String enums: more readable values
enum Genre {
Fantasy = 'FANTASY',
Mystery = 'MYSTERY',
NonFiction = 'NON_FICTION',
Biography = 'BIOGRAPHY',
}
console.log(Genre.Fantasy); // 'FANTASY' - readable in logs/debugging, unlike numeric 0Achtung: Numeric enums have a surprising property: the numbers 0, 1, 2, ... also get mapped in REVERSE internally (Genre[0] gives 'Fantasy') – string enums do NOT have this "reverse mapping". For debugging and when serializing (e.g. to JSON, where a number 0 conveys little), string enums are almost always the better choice.
When enum, when a literal union?
| Tool | Properties |
|---|---|
Literal union (type X = 'a' | 'b') | Exists ONLY at compile time (no runtime object, no extra JavaScript code). Values are plain strings – works seamlessly with JSON, APIs, databases. |
enum | ALSO exists at runtime as a real object – allows Object.values(Genre) to iterate over all values at runtime. Produces extra compiled JavaScript code. |
The modern TypeScript community clearly leans toward literal unions for MOST use cases (see the TypeScript team's own recommendation) – enum remains sensible when you genuinely need to iterate over all possible values at RUNTIME.
In practice: Genre as a literal union instead of a free string
Our current genres: string[] allows ANY arbitrary string – a typo like 'Fantsy' wouldn't be caught. Let's restrict it:
export type Genre =
| 'Fantasy'
| 'Mystery'
| 'NonFiction'
| 'Biography'
| 'Novel'
| 'ChildrensBook';// In Book.ts:
import { Genre } from './Genre.js';
export interface Book {
// ... existing fields
genres: Genre[]; // instead of string[]
}
// Now a typo gets caught IMMEDIATELY:
genres: ['Fantsy']; // error - 'Fantsy' is not a valid Genre valueTipp: This tutorial's rule of thumb: prefer literal unions for fixed value sets, unless you need GENUINE runtime iteration over all values (then enum), or you're working in an existing codebase that already consistently uses enum (then CONSISTENCY wins over personal preference, as already emphasized in chapter 8).