One of the most common questions I get about TypeScript: should I use an interface or a type? Both can describe object shapes, but they have subtle differences. Here’s when to use each.
The Quick Answer
Use interfaces for object shapes and public APIs. Use types for unions, intersections, and complex type manipulations. When in doubt, use interfaces.
Interfaces
interface User {
id: number;
name: string;
email?: string; // Optional
readonly createdAt: Date; // Read-only
}
// Extending interfaces
interface Employee extends User {
department: string;
salary: number;
}
// Declaration merging (interfaces can be extended later)
interface User {
phone?: string; // Adds to original interface
}
Type Aliases
// Object type
type User = {
id: number;
name: string;
};
// Union types - can't do this with interfaces
type Status = 'pending' | 'approved' | 'rejected';
// Intersection types
type Employee = User & {
department: string;
};
// Utility types
type PartialUser = Partial<User>;
type ReadonlyUser = Readonly<User>;
type UserKeys = keyof User; // 'id' | 'name'
Key Differences
- Declaration merging: Interfaces can be extended; types cannot
- Unions/Intersections: Only types can define unions
- Primitives: Only types can alias primitives
- Error messages: Interfaces often give better error messages
My Guidelines
// Use interface for objects
interface ApiResponse {
data: unknown;
status: number;
}
// Use type for unions
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
// Use type for function signatures
type Handler = (req: Request) => Response;
// Use type for computed/mapped types
type Nullable<T> = T | null;
References
Discover more from C4: Container, Code, Cloud & Context
Subscribe to get the latest posts sent to your email.