100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
TypeScript

Union and Intersection Types in TypeScript

Combine types with `|` (union) and `&` (intersection) to model values that can be one of several shapes or must satisfy all of them.

Type System BasicsIntermediate10 min readJul 8, 2026
Analogies

1. Introduction

Union types and intersection types let you combine existing types into new ones. A union type (A | B) describes a value that could be either type A or type B. An intersection type (A & B) describes a value that must satisfy both type A and type B simultaneously. Together they are two of the most-used tools for modeling real-world data shapes in TypeScript, from API responses to component props.

🏏

Cricket analogy: Think of a batting slot filled by either Rohit Sharma or Shubman Gill (a union) versus an all-rounder like Ravindra Jadeja who must field, bowl, and bat (an intersection) — API-response shapes work the same way.

Unions are common when a value can legitimately take multiple forms -- a function that accepts a string or a number, or a variable representing one of several states. Intersections are common when you want to merge multiple object shapes together, such as combining a base set of properties with role-specific properties.

🏏

Cricket analogy: A toss result that could be 'bat' or 'bowl' is a classic union of possible states, while a captain's profile merging base player stats with captaincy-specific fields like toss-win record is an intersection.

2. Syntax

typescript
// Union type: value is one of the listed types
let id: string | number;
id = "abc123";
id = 42;

// Intersection type: value must satisfy all listed types
interface Named { name: string; }
interface Aged { age: number; }
type Person = Named & Aged;

const p: Person = { name: "Sam", age: 30 };

3. Explanation

With a union type A | B, TypeScript only lets you directly access members that exist on BOTH A and B without first narrowing the type. To use a member that exists only on one branch of the union, you must first perform type narrowing -- using a type guard such as typeof, instanceof, an in check, a discriminant property comparison, or a user-defined type predicate (value is Foo). Once narrowed inside a conditional branch, TypeScript knows exactly which member of the union you are working with and allows access to type-specific properties.

🏏

Cricket analogy: With a Rohit Sharma-or-Jasprit Bumrah union you can only reference shared stats like matches played until you narrow with an 'in' check for 'bowlingAverage' to safely access Bumrah's bowler-only figures.

Intersection types work the opposite way for objects: A & B combines ALL properties from both A and B into a single type that must have everything. This is useful for mixins and composing smaller interfaces into a richer one. However, if you intersect incompatible primitive types -- for example string & number -- there is no value that can simultaneously be both a string and a number, so TypeScript infers the result as the never type, since no value can satisfy that constraint.

🏏

Cricket analogy: An all-rounder type formed by intersecting Batter & Bowler must carry every property from both, such as strikeRate and economyRate, but intersecting Batter & Umpire, roles that can't coexist in one match, collapses to 'never'.

Gotcha: Accessing a union type's member that isn't shared by all members without narrowing first raises a compile error ("Property does not exist on type ..."). Also, intersecting incompatible primitive types like string & number silently collapses to never -- a common source of confusing errors when combining generic type parameters.

4. Example

typescript
type Cat = { kind: "cat"; meow(): string };
type Dog = { kind: "dog"; bark(): string };
type Pet = Cat | Dog;

function speak(pet: Pet): string {
  // Narrowing with a discriminant property before accessing kind-specific methods
  if (pet.kind === "cat") {
    return pet.meow();
  } else {
    return pet.bark();
  }
}

const cat: Cat = { kind: "cat", meow: () => "Meow!" };
const dog: Dog = { kind: "dog", bark: () => "Woof!" };

console.log(speak(cat));
console.log(speak(dog));

// Intersection combining two shapes
interface HasId { id: number; }
interface HasName { name: string; }
type Entity = HasId & HasName;

const entity: Entity = { id: 1, name: "Widget" };
console.log(entity);

5. Output

text
Meow!
Woof!
{ id: 1, name: 'Widget' }

6. Key Takeaways

Practice what you learned

Was this page helpful?

Topics covered

#TypeScript#TypeScriptProgrammingStudyNotes#Programming#UnionAndIntersectionTypesInTypeScript#Union#Intersection#Types#Syntax#StudyNotes#SkillVeris