Types vs Interfaces
Both define object shapes. Use interface by default; switch to type when you need unions, intersections, or mapped types.
Quick Comparison
| Feature | interface | type |
|---|---|---|
| Object shape | Yes | Yes |
| Extend/inherit | extends | & intersection |
| Declaration merging | Yes | No |
| Union types | No | Yes |
| Mapped types | No | Yes |
Class implements | Yes | No |
Interface: Declaration Merging
Interfaces with the same name merge automatically:
interface Point {
x: number;
}
interface Point {
y: number;
}
// Point now has both x and y
const p: Point = { x: 1, y: 2 };
This is how libraries extend built-in types (like adding properties to Window).
Type: Unions and Computed Types
Types handle things interfaces can’t:
type Result = "success" | "error" | "pending"; // union of literals
type Callback = (data: string) => void; // function type
type Pair<T> = [T, T]; // tuple
type Keys = keyof User; // computed from another type
Rule of Thumb
Use interface for object shapes in public APIs (classes, props, configs). Use type for unions, function signatures, and computed types.
// Interface: describes a thing
interface User {
name: string;
email: string;
}
// Type: describes a computation or union
type Status = "active" | "inactive";
type UserWithStatus = User & { status: Status };