Using Literal and Union Types
Learn how to constrain types precisely using literal types and model flexible behavior using unions while avoiding pitfalls from ambiguity.
We’ve already met union and literal types like "admin" | "editor"
and string | null
. But if that’s all we’re doing with them, we’re not really using TypeScript—we’re just naming things.
This lesson covers how to constrain values, build variant logic without enums, and avoid the kind of ambiguity that leaves our logic error-prone.
Literal types: Values as types
In JavaScript, we think of "dark"
as a value. In TypeScript, we can make it a type.
This is the essence of a literal type: a concrete, exact value like "light"
, 42
, or true
being treated as a type. It’s no longer one value among many—it’s the only valid value.
Let’s compare two assignments:
let mode: "dark" = "dark"; // ✅mode = "light"; // ❌ Error: "light" is not assignable to "dark"console.log(`Mode: ${mode}`);
This is different from:
{"compilerOptions": {"target": "ES2020","module": "commonjs","strict": true}}
When we say string
, we allow every possible string. But when we say "dark"
, we restrict it to that exact value.
Literal types with primitives
Literal types work with more than just strings. Numbers, booleans, even null
and undefined
can all be used as literal types.
Here’s how we use them to model fixed states:
type Enabled = true;type Level = 3;type Nothing = null;const isEnabled: Enabled = true;const priority: Level = 3;const value: Nothing = null;console.log(`Enabled: ${isEnabled}, Priority: ${priority}, Value: ${value}`);
Explanation:
Lines 1–3: Define literal types that represent specific primitive values.
Lines 5–7: Use those types to constrain variables to accept only that exact value.
These aren’t just values—they’re constraints. By treating exact values as types, we lock in intent and prevent unintended changes. This level of precision pays off fast when building config structures, flags, or anything where only one value is correct.
Literal types with objects and tuples
Literal types aren’t just atomic. With the help of as const
, we can turn entire values—objects, arrays, tuples—into literal types.
{"compilerOptions": {"target": "ES2020","module": "commonjs","strict": true}}
Explanation:
Lines 1–4: Define an object and apply
as const
, freezing both property values and their types.Line 6:
typeof config
extracts the literal type from the value, preserving the exact structure....