Appearance
Union Types
Union types allow a value to be one of several types. They're one of TypeScript's most powerful features for handling values that can have multiple possible types.
Basic Type Unions
A union type is defined using the | (pipe) operator. Use it wherever you put a type annotation.
ts
// 1. Simple union without type alias:
let value: number | string = 0;
value = 42; // OK - can assign number
value = "hello"; // OK - can assign string
// value = true; // Error - boolean not allowed
// 2. Using a type alias:
type BooleanNumberString = boolean | number | string;
let mixedValue: BooleanNumberString = false;
mixedValue = true; // OK - can assign boolean
mixedValue = 100; // OK - can assign number
mixedValue = "world"; // OK - can assign string
// mixedValue = null; // Error - null not allowedundefined and implicit types
When you declare a variable without an initial value, TypeScript infers it as a union with undefined. This happens because the variable could legitimately be undefined until it's assigned a value.
ts
// Variable declared without initial value:
let count: number;
// count is actually typed as: number | undefined
// This would cause an error because count might be undefined:
// console.log(count + 1); // Error: Object is possibly 'undefined'
// Assign a value first:
count = 42;
console.log(count + 1); // OK - now count is definitely a numberWe'll see later how type narrowing is used in this situation.
Unions of Values
You can annotate variables that have a type defined as a specific set of values.
ts
// Variable that can only be 0, 1, or 2:
let direction: 0 | 1 | 2;
direction = 0; // OK
direction = 1; // OK
direction = 2; // OK
// direction = 3; // Error: Type '3' is not assignable to type '0 | 1 | 2'
// Variable with mixed types - can only hold "hello", false, or 42:
let weirdValue: "hello" | false | 42;
weirdValue = "hello"; // OK
weirdValue = false; // OK
weirdValue = 42; // OK
// weirdValue = "world"; // Error: Type '"world"' is not assignable
// weirdValue = true; // Error: Type 'true' is not assignableA common idiom is to define a type union of strings to work like an enum, providing type safety for a set of predefined values:
ts
// Status union that works like an enum:
type Status = "idle" | "loading" | "success" | "error";
let currentStatus: Status = "idle";
currentStatus = "loading"; // OK
currentStatus = "success"; // OK
currentStatus = "error"; // OK
// currentStatus = "pending"; // Error: Type '"pending"' is not assignable
// Function that only accepts valid status values:
function updateStatus(status: Status) {
console.log(`Status changed to: ${status}`);
}
updateStatus("loading"); // OK
updateStatus("success"); // OK
// updateStatus("invalid"); // Error: Argument not assignable❌ TypeScript has an enum type, but you really shouldn't use it. In recent years, the philosophy of TypeScript is to only use annotations that can be "stripped" to leave standard JavaScript. The TypeScript enum has to be transpiled into very different JavaScript to work in the browser, and this is best avoided.
Union Types with Objects
Union types can combine different object shapes:
ts
type Circle = { kind: "circle"; radius: number };
type Square = { kind: "square"; size: number };
type Triangle = { kind: "triangle"; base: number; height: number };
type Shape = Circle | Square | Triangle;
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.size ** 2;
case "triangle":
return (shape.base * shape.height) / 2;
}
}
// Usage:
const circle: Circle = { kind: "circle", radius: 5 };
const square: Square = { kind: "square", size: 10 };
console.log(getArea(circle)); // ~78.54
console.log(getArea(square)); // 100Union Types with Arrays
You can create union types for arrays:
ts
type StringOrNumberArray = (string | number)[];
const mixedArray: StringOrNumberArray = ["hello", 42, "world", 100];
console.log(mixedArray); // ["hello", 42, "world", 100]External Resources