type
vs interface
in TypeScript
In TypeScript, both type
and interface
can be used to describe the shape of objects. However, they have important differences that affect scalability, composability, and predictability—especially in modern Next.js projects using TypeScript.
This guide outlines the key differences and when to prefer type
over interface
.
✅ Why Use type
1. Supports Unions and Intersections
type
makes it easy to compose multiple types together:
type Result = Success | Failure;
type Combined = Base & Extra;
Interfaces cannot express union types.
2. Handles Non-Object Types
type
works with primitives, tuples, and function signatures:
type Status = 'idle' | 'loading' | 'error';
type Point = [number, number];
type ClickHandler = (event: MouseEvent) => void;
interface
is limited to describing object-like shapes.
3. Immutable by Design
type
aliases are closed — you can’t reopen or merge them later:
type User = { id: string };
// Cannot be redefined elsewhere
This helps prevent accidental type merging across files/modules.
🤔 When to Use interface
There are still cases where interface
is useful:
- Extending framework types (e.g.
React.ComponentProps
) - Public APIs where declaration merging is intentional
- Class-based or OOP-style codebases
✨ Recommendation
For most modern Next.js + TypeScript projects:
✅ Use
type
by default
🤝 Useinterface
only when you need structural extendability or declaration merging
Example
interface
(legacy style):
interface User {
id: string;
name: string;
}
type
(recommended):
type User = {
id: string;
name: string;
};
Summary Table
Feature | type | interface |
---|---|---|
Object shapes | ✅ | ✅ |
Union & intersection types | ✅ | ❌ |
Primitives, tuples, functions | ✅ | ❌ |
Declaration merging | ❌ | ✅ |
Extendability | ✅ (& ) | ✅ (extends ) |
Best for composition | ✅ | ❌ |
Recommended default | ✅ | ❌ |
Conclusion
Favoring type
ensures better composability, more predictable behavior, and consistency across different kinds of type definitions in a modern TypeScript codebase.