TS

TypeScript Fundamentals

17 lessons

Progress0%
1. Introduction to TypeScript
1What is TypeScript?2Setting Up TypeScript
2. Basic Types
1Primitive Types2Interfaces and Type Aliases
3. Functions and Generics
Typed FunctionsGenerics
4. Classes and OOP
ClassesInheritance and Interfaces
5. Advanced Types
Union and Intersection TypesUtility Types
6. Modules and Decorators
ES Modules
7. Decorators
Class & Method DecoratorsProperty & Parameter Decorators
8. Declaration Files
Writing .d.ts Files@types & DefinitelyTyped
9. Advanced Patterns
Conditional Types & inferTemplate Literal Types & satisfies
All Tutorials
TypeScriptAdvanced Types
Lesson 9 of 17 min
Chapter 5 · Lesson 1

Union and Intersection Types

Union and Intersection Types

Union types (|) A union type means a value can be one of several types:

ts
type StringOrNumber = string | number;

You must narrow the type before using type-specific operations.

Intersection types (&) An intersection combines multiple types into one, requiring all members to be present:

ts
type Admin = User & { role: "admin" };

Discriminated unions Add a common literal-type field (the discriminant) to each member of a union. TypeScript's control-flow analysis then narrows the type automatically inside if or switch blocks.

Type narrowing

  • typeof – narrows primitive types ("string", "number", "boolean", "object", "function", etc.).
  • instanceof – narrows class instances.
  • in operator – narrows by checking property presence.
  • Assignment and truthiness checks also narrow types.

Best practice: prefer discriminated unions over ad-hoc typeof checks for complex variant types.

Code Examples

Union types and typeof narrowingtypescript
function formatId(id: string | number): string {
  if (typeof id === "string") {
    return id.toUpperCase();
  }
  return id.toFixed(0);
}

console.log(formatId("abc-123"));
console.log(formatId(42));

Inside the if branch TypeScript knows id is string, so toUpperCase() is safe. After the branch it is number.

Discriminated unionstypescript
type Circle = { kind: "circle"; radius: number };
type Rectangle = { kind: "rect"; width: number; height: number };
type Shape = Circle | Rectangle;

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "rect":
      return shape.width * shape.height;
  }
}

console.log(area({ kind: "circle", radius: 5 }).toFixed(2));
console.log(area({ kind: "rect", width: 4, height: 6 }));

The kind discriminant lets TypeScript narrow the type in each case branch, giving you full access to the right properties.

Intersection typestypescript
type Timestamped = { createdAt: Date };
type Named = { name: string };
type Entity = Timestamped & Named & { id: number };

function createEntity(name: string): Entity {
  return { id: Math.random(), name, createdAt: new Date() };
}

const e = createEntity("Product");
console.log(e.name);
console.log(typeof e.createdAt);
console.log(typeof e.id);

Intersection types compose multiple shapes. An Entity must satisfy all three constituent types simultaneously.

Quick Quiz

1. What is a discriminated union?

2. What does `A & B` mean in TypeScript?

Was this lesson helpful?

PreviousNext