In TypeScript, both type
and interface
are used to define the shape and behavior of objects, but knowing when to use one over the other can make a big difference in code readability and maintainability. In this post, we'll explore when it's more appropriate to use type
or interface
, with practical examples and clear guidelines.
1. Defining Object Shapes
When to Use interface
-
Use
interface
when you need to define the structure of an object or when you want to define contracts that can be implemented by classes.
Example:
interface User {
name: string;
age: number;
}
const user: User = {
name: "Alice",
age: 25,
};
Why use interface
here?
-
interface
is ideal for representing objects, especially when you need something that can be extended or implemented by classes.
When to Use type
-
Use
type
when you need more flexibility, such as creating complex types, unions, or intersections.
Example:
type User = {
name: string;
age: number;
};
Why use type
here?
- While both
type
andinterface
can define object shapes,type
is preferable if you need to combine types later (e.g., in unions or intersections).
2. Extending Objects
When to Use interface
-
Use
interface
if you need to extend an object type multiple times, especially in large projects.
Example:
interface User {
name: string;
age: number;
}
interface Admin extends User {
role: string;
}
const admin: Admin = {
name: "Bob",
age: 30,
role: "Administrator",
};
Why use interface
here?
- The
extends
syntax in interfaces is clear and intuitive, making it easier to read and maintain code.
When to Use type
-
Use
type
to combine types using intersections (&
) in cases where you don't need direct inheritance.
Example:
type User = {
name: string;
age: number;
};
type Admin = User & {
role: string;
};
const admin: Admin = {
name: "Bob",
age: 30,
role: "Administrator",
};
Why use type
here?
-
type
is ideal for explicitly combining types, especially in complex types.
3. Merging Definitions
When to Use interface
-
Use
interface
if you need to automatically merge type definitions, such as when working with third-party libraries or defining contracts in a large system.
Example:
interface User {
name: string;
}
interface User {
age: number;
}
const user: User = {
name: "Alice",
age: 30,
};
Why use interface
here?
- With
interface
, TypeScript automatically merges definitions, which can be useful when working with modules and libraries that may extend already-defined types.
When to Use type
-
Avoid using
type
if you need automatic merging, as TypeScript does not allow mergingtype
definitions.
Example (not allowed):
type User = {
name: string;
};
type User = {
age: number;
}; // Error: Duplicate identifier 'User'.
Why not use type
here?
-
type
does not support merging, making it less flexible for scenarios where you need to extend or complement type definitions.
4. Classes and Implementations
When to Use interface
-
Use
interface
when defining contracts for classes, especially in object-oriented programming scenarios.
Example:
interface User {
name: string;
age: number;
}
class Person implements User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
Why use interface
here?
-
interface
is the natural choice for defining what a class should implement, maintaining compatibility with object-oriented programming patterns.
When to Use type
-
Avoid using
type
to implement classes, asinterface
is more intuitive and better supported for this purpose.
Example (not common):
type User = {
name: string;
age: number;
};
class Person implements User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
Why not use type
here?
-
interface
is designed for implementation contracts, whiletype
is better suited for more complex types, not necessarily for class contracts.
5. Complex Types: Unions and Intersections
When to Use type
-
Use
type
to create complex types, such as unions and intersections, whereinterface
does not offer support.
Example with Unions:
type Status = "success" | "error" | "loading";
const currentStatus: Status = "success";
Example with Intersections:
type Response = {
message: string;
};
type Error = {
code: number;
};
type APIResponse = Response & Error;
const apiResponse: APIResponse = {
message: "Not Found",
code: 404,
};
Why use type
here?
-
type
is extremely powerful for creating composite and dynamic types, allowing combinations thatinterface
cannot handle.
Summary: When to Use type
or interface
-
Use
interface
:- To define object structures and when you expect the object to be extended or implemented by classes.
- When you need automatic definition merging.
- When defining class contracts.
-
Use
type
:- For unions, intersections, and more complex types.
- When you need flexibility to create dynamic types.
- When you want to explicitly combine types.
By understanding these contexts and differences, you can make more informed decisions about when to use type
or interface
in TypeScript, resulting in cleaner, more robust, and maintainable code.
These are just suggestions, so feel free to share your thoughts in the comments!
Top comments (2)
Great post! I saw a lot of advice to “just pick one and be consistent” when I first started with TS. You’ve very clearly presented the strengths of both, though.
I think this is going to be saved as my go-to reference when some asks me or I’m onboarding first-time TS devs to a project.
I really appreciate that!