What is the difference between these statements (interface vs type) in TypeScript?
In TypeScript, both type and interface can describe object shapes (i.e., what properties an object has), and for many basic use cases, they act very similarly. However, there are a few differences in capabilities, syntax, and how the compiler treats them. Below is a concise breakdown:
1. Basic Examples
interface
interface Person {
name: string;
age: number;
}
Recommended Courses
type
type Person = {
name: string;
age: number;
};
In these simple examples, both define an object shape and can be used interchangeably for most purposes (e.g., function parameters, variable annotations, etc.). They both define the shape Person { name: string; age: number }.
2. Key Differences
Declaration Merging (Extending/Reopening)
- Interfaces support declaration merging, meaning you can define the same interface in multiple places and TypeScript will merge them.
interface Person { name: string; } interface Person { age: number; } // Merged: { name: string; age: number } const p: Person = { name: 'Alice', age: 30 }; - Type aliases do not support declaration merging. If you try to write the same
typename in multiple places, you’ll get a redefinition error.
- Interfaces support declaration merging, meaning you can define the same interface in multiple places and TypeScript will merge them.
Extending vs. Intersection
- Interfaces use the
extendskeyword to inherit from other interfaces.interface Animal { name: string; } interface Bear extends Animal { honey: boolean; } - Type aliases can use intersections (
&) to combine object types:type Animal = { name: string; }; type Bear = Animal & { honey: boolean; }; - Result wise, they can achieve a similar effect, but the syntax is different.
- Interfaces use the
Union and Other Advanced Types
- Type aliases can represent unions, primitives, or more advanced constructs:
type StringOrNumber = string | number; type Coordinates = [number, number]; type Callback = (x: number) => string; - Interfaces cannot represent these things directly (e.g., you cannot create an interface that is “string or number”).
- Type aliases can represent unions, primitives, or more advanced constructs:
Name Conflicts & Error Messages
- Error and IntelliSense messages can be more straightforward with interfaces because they show up by name in many places.
- Type aliases sometimes produce more expanded or less direct error messages (especially for large or deeply nested types).
Recommended for Library Declarations
- Many prefer interfaces for public library .d.ts because they can be reopened (declaration merging) by other consumers, e.g., adding new properties to an existing interface in a third-party library.
- Type aliases can be more flexible for complex or composite scenarios in application code.
3. Which One to Use?
Use
interfacewhen:- You want to describe the shape of objects in a straightforward manner (especially in public APIs).
- You expect consumers might need to merge declarations (for adding properties in a library).
- You want extendable or re-openable definitions.
Use
typewhen:- You need advanced type features (unions, mapped types, etc.).
- You prefer to define function signatures, tuple types, or union types more succinctly.
- You want to intersect multiple object types (
type Combined = A & B & {...}).
In many cases, either can represent an object shape. Team or style guide preferences often matter more than a purely technical reason. But the key distinctions (declaration merging, advanced types, union usage) are typically the deciding factors.
Recommended Resource
Bottom Line
- Interfaces are extendable, can be reopened, and are great for object shapes in library/public API definitions.
- Type aliases are more flexible for advanced type constructs (unions, tuples, primitives, etc.) and may produce slightly different compiler output and error messages.
Either way, both provide strong type-checking for your TypeScript code—choose the one that best fits your extensibility or type complexity needs.