Skip to content
intermediatePhase 35 · TypeScript

Union Types

Combine multiple types with union (|) and narrow with type guards.

30m
0 problems
Topic Progress0%

Union Syntax

Union Syntax

Union types allow a value to be one of several types, using the | operator.

Basic Union

// A value can be string OR number
let id: string | number;

id = "abc123"; // OK
id = 123; // OK
// id = true; // Error!

Union with Literals

type Direction = "up" | "down" | "left" | "right";
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

function move(direction: Direction): void {
  console.log(`Moving ${direction}`);
}

move("up"); // OK
// move("forward"); // Error!

Union of Object Types

type Success = {
  status: "success";
  data: string[];
};

type Error = {
  status: "error";
  message: string;
};

type Result = Success | Error;

function handleResult(result: Result) {
  if (result.status === "success") {
    console.log(result.data); // OK
  } else {
    console.log(result.message); // OK
  }
}

Function Parameters

function format(input: string | number): string {
  if (typeof input === "string") {
    return input.toUpperCase();
  } else {
    return input.toFixed(2);
  }
}

Type Narrowing

Type Narrowing

Type narrowing is the process of refining a union type to a more specific type using type guards.

typeof Guards

function process(value: string | number | boolean) {
  if (typeof value === "string") {
    // TypeScript knows value is string
    return value.toUpperCase();
  } else if (typeof value === "number") {
    // TypeScript knows value is number
    return value.toFixed(2);
  } else {
    // TypeScript knows value is boolean
    return value ? "yes" : "no";
  }
}

instanceof Guards

class Dog {
  bark() { return "Woof!"; }
}

class Cat {
  meow() { return "Meow!"; }
}

function makeSound(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    return animal.bark();
  } else {
    return animal.meow();
  }
}

Truthiness Guards

function printName(name: string | null) {
  if (name) {
    // TypeScript knows name is string
    console.log(name.toUpperCase());
  }
}

'in' Operator

type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

Discriminated Unions

Discriminated Unions

Discriminated unions use a common property (discriminant) to distinguish between types.

Basic Pattern

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rectangle"; width: number; height: number }
  | { kind: "triangle"; base: 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;
    case "triangle":
      return (shape.base * shape.height) / 2;
  }
}

Exhaustive Checking

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "rectangle":
      return shape.width * shape.height;
    case "triangle":
      return (shape.base * shape.height) / 2;
    default:
      const _exhaustive: never = shape;
      return _exhaustive;
  }
}

Real-World Example

type Action =
  | { type: "INCREMENT"; amount: number }
  | { type: "DECREMENT"; amount: number }
  | { type: "RESET" };

function reducer(state: number, action: Action): number {
  switch (action.type) {
    case "INCREMENT":
      return state + action.amount;
    case "DECREMENT":
      return state - action.amount;
    case "RESET":
      return 0;
  }
}

Practice Problems

0/3solved
Build Union Types Component

Create a reusable React component implementing Union Types. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Union Types Testing

Write unit and integration tests for Union Types using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Union Types Performance

Optimize Union Types for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What operator creates a union type?

Question 1 options

2. What is a discriminated union?

Question 2 options

3. What is type narrowing?

Question 3 options

4. What does exhaustive checking ensure?

Question 4 options

Flashcards

Question

How do you create a union type?

Answer

Use the pipe operator: string | number

Question

What is a type guard?

Answer

An expression that checks the type at runtime

Question

What is a discriminated union?

Answer

A union with a common literal property for discrimination

Question

What is the never type used for in discriminated unions?

Answer

Exhaustive checking to ensure all cases are handled

Question

What is Union Types?

Answer

Union Types is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Union types allow a value to be one of several types
  • 2.Type guards narrow types using typeof, instanceof, or in
  • 3.Discriminated unions use a common property to distinguish types
  • 4.Exhaustive checking ensures all union cases are handled
  • 5.Union types are powerful for modeling state

Interview Tips

  • Explain discriminated unions and their benefits
  • Show how type narrowing works with typeof and instanceof
  • Discuss exhaustive checking with the never type

Cheat Sheet

Cheat Sheet

Union Syntax

type ID = string | number;
type Status = "active" | "inactive";

Type Guards

if (typeof x === "string") { }
if (x instanceof Error) { }
if ("prop" in x) { }

Discriminated Unions

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rect"; w: number; h: number };

switch (shape.kind) {
  case "circle": // ...
  case "rect": // ...
}

Exhaustive Check

default:
  const _: never = shape;
  return _;