Hint
interface is extendable and mergeable; type is more powerful (unions, tuples, mapped types) but not mergeable
Both define object shapes, but they have different capabilities:
Interface — designed for object/class shapes, supports declaration merging:
interface User {
id: number;
name: string;
}
// Extending interfaces
interface Admin extends User {
adminLevel: number;
}
// Declaration merging — useful for augmenting library types
interface Window {
myCustomProp: string; // adds to existing Window interface
}
// Implementing in a class
class ConcreteUser implements User {
constructor(public id: number, public name: string) {}
}
Type alias — more powerful, works with any type including primitives, unions, tuples, and mapped types:
// Primitive alias
type ID = string | number;
// Union — interfaces can't do this
type Status = 'active' | 'inactive' | 'pending';
// Tuple
type Pair = [string, number];
// Mapped type — only type aliases can do this directly
type Readonly<T> = { readonly [K in keyof T]: T[K] };
// Conditional type
type NonNullable<T> = T extends null | undefined ? never : T;
Practical guidance:
interface for component props and type for everything else. Both work for most cases — pick a style and stick to it.