Skip to content

Union Types

Union types allow a value to be one of several types. Introduced early in TypeScript, they enable flexible yet type-safe code when a value could have multiple valid types.

Without union types, you’d use any (losing type safety):

// Loses all type checking
function formatValue(value: any): string {
if (typeof value === "number") {
return value.toFixed(2);
}
return value.toString();
}

Union types maintain type safety:

// Type-safe with union
function formatValue(value: string | number): string {
if (typeof value === "number") {
return value.toFixed(2);
}
return value.toUpperCase(); // TypeScript knows it's a string here
}
// Multiple types
let id: string | number;
id = "abc123"; // OK
id = 12345; // OK
id = true; // Error!
// Arrays with unions
let mixed: (string | number)[] = [1, "two", 3, "four"];
// Null/undefined unions
let userName: string | null = null;
let age: number | undefined;
// Function return types
function getUser(id: string): User | null {
return users.find(u => u.id === id) || null;
}
// Type guards for narrowing
function process(value: string | number) {
if (typeof value === "string") {
// TypeScript knows value is string here
console.log(value.toUpperCase());
} else {
// TypeScript knows value is number here
console.log(value.toFixed(2));
}
}
  • Type safety: Better than any, catches errors
  • Flexibility: Handle multiple types when needed
  • Autocomplete: IDE knows possible types
  • Documentation: Types serve as inline documentation
  • Narrowing: Type guards refine type within blocks
  • Use type guards (typeof, instanceof, custom guards) to narrow types
  • Intersection types (A & B) are different from unions (A | B)
  • Can combine with type aliases for readability
  • Union with never type is just the other type
  • Order doesn’t matter in unions
// Type alias for readability
type ID = string | number;
type Response = Success | Error;
// Discriminated unions (tagged unions)
type Shape =
| { kind: "circle"; radius: number }
| { kind: "rectangle"; width: number; height: number };
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "rectangle":
return shape.width * shape.height;
}
}
  1. Create a variable that accepts string, number, or boolean

    Answer
    let value: string | number | boolean;
  2. Write a function that returns either a User object or null

    Answer
    function findUser(id: string): User | null {
    // implementation
    }
  3. What’s the difference between string | number and string & number?

    Answer `string | number` is a union (value can be string OR number). `string & number` is an intersection (impossible - a value can't be both simultaneously, results in `never`).