TypeScript Union and Intersection Types
Master union and intersection types for flexible, type-safe code.
Union Types (OR relationship)
type ID = string | number;
function printID(id: ID) {
console.log(`ID: ${id}`);
}
printID(101); // ✅ OK
printID("ABC123"); // ✅ OKDiscriminated Unions
type Result<T> =
| { success: true; data: T }
| { success: false; error: string };
function handleResult<T>(result: Result<T>) {
if (result.success) {
console.log(result.data);
} else {
console.log(result.error);
}
}Real-World: Loading States
type LoadingState =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: User[] }
| { status: "error"; error: Error };
function renderUsers(state: LoadingState) {
switch (state.status) {
case "idle":
return "Click to load";
case "loading":
return "Loading...";
case "success":
return state.data.map(u => u.name).join(", ");
case "error":
return `Error: ${state.error.message}`;
}
}Intersection Types (AND relationship)
interface Person {
name: string;
age: number;
}
interface Employee {
employeeId: string;
department: string;
}
type Staff = Person & Employee;
const employee: Staff = {
name: "Alice",
age: 30,
employeeId: "E123",
department: "Engineering"
};Real-World: API Response
interface BaseResponse {
timestamp: Date;
requestId: string;
}
interface SuccessResponse<T> extends BaseResponse {
success: true;
data: T;
}
interface ErrorResponse extends BaseResponse {
success: false;
error: { code: string; message: string };
}
type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;Complex Example: Form Fields
interface BaseField {
name: string;
label: string;
}
interface TextField extends BaseField {
type: "text";
maxLength?: number;
}
interface NumberField extends BaseField {
type: "number";
min?: number;
max?: number;
}
type FormField = TextField | NumberField;
function renderField(field: FormField) {
switch (field.type) {
case "text":
return `<input type="text" />`;
case "number":
return `<input type="number" />`;
}
}Quick Reference
| Pattern | Symbol | Example | | ------------ | ------ | --------------------- | | Union | | | string | number | | Intersection | & | Person & Employee |
Best Practices
1. Use unions for "or" relationships 2. Use intersections for "and" relationships 3. Prefer discriminated unions for state 4. Add type guards for narrowing
Conclusion
- Union Types: Value can be one of several types
- Intersection Types: Combine multiple types
- Discriminated Unions: Type-safe state machines
Master these for robust TypeScript!
Topic Hub
Frontend Architecture / Tooling
Architecture, platform choices, and AI-assisted development workflows.
Open Frontend Architecture / Tooling hubRelated Reading
14 min read
Serverless & Edge Architecture for Full-Stack Apps
Master serverless and edge computing patterns for building scalable, cost-effective full-stack applications. Learn when to use each approach and how to implement them.
12 min read
AI-Assisted Development Tools Every Web Developer Should Use in 2025
Discover the AI-powered tools transforming web development workflows, from code generation to design-to-code, and how to integrate them effectively.
Need a frontend roadmap that supports growth, not churn?
I help product and marketing teams simplify stack decisions, reduce frontend drag, and ship faster without creating long-term maintenance debt.
Written by Salman Izhar
Frontend Developer specializing in React, Next.js, and building high-converting web applications.
Learn More