Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

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 values

Literal 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 0

enum 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 0

Achtung: 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?

ToolProperties
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.
enumALSO 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:

src/models/Genre.ts
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 value

Tipp: 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).