Interfaces & Type Aliases
Define object shapes, contracts, and reusable type definitions with interfaces and type aliases.
Interfaces for Object Shapes
Interfaces describe the shape of objects — property names, types, and optionality. They are ideal for public API contracts, React component props, and service boundaries that multiple modules consume.
Interfaces support declaration merging: two declarations with the same name merge into one. This is useful for augmenting third-party module types but can surprise teams if overused in application code.
- Describe object property contracts
- Declaration merging for module augmentation
- Best for public API surfaces
interface User {
id: string;
name: string;
email?: string;
}Type Aliases for Flexibility
Type aliases name any type — unions, intersections, primitives, tuples, and mapped types. Use them when the type is not a plain object shape or when composing complex unions.
`type ID = string | number` and `type Result<T> = { ok: true; data: T } | { ok: false; error: string }` are idiomatic alias patterns. Aliases do not merge — each name is a single definition.
- Alias any type, not just objects
- Unions and discriminated results
- No declaration merging
type Status = 'pending' | 'active' | 'archived';
type ApiResult<T> = { data: T } | { error: string };Extending and Intersecting
Interfaces extend with `extends` keyword, creating subtypes that inherit properties. Type aliases combine with `&` intersection: `type Admin = User & { permissions: string[] }`.
For overlapping object types, intersections merge properties; conflicting property types become an intersection of those types (often `never` if incompatible). Prefer `extends` for OOP-style hierarchies and `&` for compositional mixing.
- `extends` for interface inheritance
- `&` for type intersection
- Watch for incompatible property conflicts
interface Employee extends User {
department: string;
}Readonly and Optional Properties
`readonly` prevents reassignment after initialization — use for IDs and immutable config. Optional properties (`?`) allow absence; access them with optional chaining or explicit undefined checks.
`Readonly<T>` utility makes all properties readonly. Combine with `ReadonlyArray<T>` or `readonly T[]` for immutable collections in state management patterns.
- `readonly` for immutable fields
- Optional `?` for absent properties
- `Readonly<T>` utility for deep immutability hints
interface Config {
readonly apiUrl: string;
debug?: boolean;
}Choosing Interface vs Type
Convention varies by team: many codebases use `interface` for object shapes and `type` for everything else. Performance differences are negligible — choose for readability and tooling behavior.
Use interfaces when you expect augmentation or extension by other modules. Use type aliases for unions, mapped types, and conditional types. Consistency within a codebase matters more than the specific rule.
- Interface for extensible object contracts
- Type alias for unions and advanced types
- Team consistency over dogma