Type vs Interface in TypeScript: When Each One Is Actually Better
The real differences between type aliases and interfaces — declaration merging, unions, performance and error messages — with a simple rule for choosing.
Table of contents
- What only type can do
- What only interface can do
- Differences that are usually overstated
- A rule that holds up
- Frequently asked questions
- Can an interface extend a type alias?
- Can a type alias implement an interface in a class?
- Which shows better in editor hover?
- Does declaration merging work across files?
- Related reading
- References
For describing an object shape, type and interface are almost interchangeable. The differences are few but each one matters in a specific situation.
What only type can do#
Type aliases name any type, not just object shapes.
type Status = 'idle' | 'loading' | 'error'; // union
type Point = [number, number]; // tuple
type Handler = (event: Event) => void; // function
type Keys = keyof User; // computed
type Maybe<T> = T | null; // wrapping a non-objectNone of these can be an interface. If you need a union — and discriminated unions are one of TypeScript's best features — you need type.
type Result<T> = { ok: true; value: T } | { ok: false; error: string };What only interface can do#
Declaration merging. Two interfaces with the same name combine:
interface Window {
myApp: { version: string };
}
// Merges with the DOM's Window rather than replacing itThis is essential for augmenting types you do not own — the Window object, an Express Request, a library's option bag. A type with the same name is a duplicate-identifier error.
// Extending a third-party module's types
declare module 'express' {
interface Request {
user?: { id: string };
}
}If you are writing a library whose types consumers may need to extend, interface is the right choice for that reason alone.
Differences that are usually overstated#
Extends vs intersection. Both compose:
interface Admin extends User {
role: 'admin';
}
type Admin = User & { role: 'admin' };extends checks compatibility eagerly and errors if you conflict with the parent. An intersection silently produces never for the conflicting property:
interface A {
x: string;
}
interface B extends A {
x: number;
} // Error: incompatible
type C = { x: string } & { x: number }; // No error — C['x'] is neverThe interface behaviour is better: it fails at the declaration instead of at some distant use site.
Performance. extends creates a cached, named relationship; large intersection chains are re-evaluated. On a small project this is unmeasurable. On a very large one, the TypeScript team's own guidance is that interfaces check faster.
Error messages. Interfaces keep their name in errors. A deeply nested intersection often gets expanded into a wall of structural detail.
A rule that holds up#
Use interface for object shapes. Use type for everything else.
// Object shapes → interface
interface User {
id: string;
email: string;
}
interface Props {
user: User;
onSave: () => void;
}
// Everything else → type
type Role = 'admin' | 'viewer';
type UserUpdate = Partial<User>;
type Reducer<S, A> = (state: S, action: A) => S;This is close to what the TypeScript handbook itself recommends, and it means the choice is never a discussion in code review.
Frequently asked questions#
Can an interface extend a type alias?#
Yes, as long as the alias resolves to an object shape: interface A extends SomeObjectType {} works. It cannot extend a union.
Can a type alias implement an interface in a class?#
class C implements SomeType works for both, provided the type is an object shape.
Which shows better in editor hover?#
Interfaces, generally. Hovering a type alias often expands the whole structure, while an interface shows its name. type Prettify<T> = { [K in keyof T]: T[K] } & {} is a common trick to force readable expansion.
Does declaration merging work across files?#
Yes, within the same module scope or global scope. That is precisely what makes it useful for augmentation — and also why an accidental duplicate interface name silently merges instead of erroring.