1. Basic Interface
An interface is used to define the shape of an object. It can define the structure that objects should follow.
interface User {
id: number;
name: string;
email: string;
}
const user: User = {
id: 1,
name: "John Doe",
email: "john.doe@example.com"
};
When to use:
- Use an interface when you want to define the structure of an object, especially when the object is intended to be implemented or extended by classes.
2. Type Alias
Type aliases are used to give a name to any type. They can define the structure of an object similar to an interface, but they are more flexible.
type User = {
id: number;
name: string;
email: string;
};
const user: User = {
id: 1,
name: "John Doe",
email: "john.doe@example.com"
};
When to use:
- Use a type alias when you need more flexibility (e.g., union types, intersection types).
- Suitable when you don't need to extend or implement the structure in classes.
3. Generic Interface
A generic interface allows you to define a structure that can work with different types, making it reusable.
interface ApiResponse<T> {
status: number;
data: T;
error?: string;
}
const userResponse: ApiResponse<User> = {
status: 200,
data: {
id: 1,
name: "John Doe",
email: "john.doe@example.com"
}
};
const productsResponse: ApiResponse<Product[]> = {
status: 200,
data: [
{ id: 1, name: "Laptop", price: 1000 },
{ id: 2, name: "Phone", price: 500 }
]
};
When to use:
- Use a generic interface when you need a structure that can work with different data types, making it reusable across various scenarios.
- Ideal for handling responses in API services where the data type can vary.
4. Type with Union
Type aliases can be used to create union types, which is one of the key advantages of using types over interfaces.
type Status = "success" | "error" | "loading";
const status: Status = "success"; // Valid
// const invalidStatus: Status = "failed"; // Error: Type '"failed"' is not assignable to type 'Status'.
When to use:
- Use type aliases when you need to define a union or intersection of multiple types.
- Suitable for defining limited sets of values, like enums.
Which One is Suitable?
-
Interfaces: Best for defining object shapes, especially when working with classes or when you need to extend or implement the structure.
-
Type Aliases: More flexible and suitable when working with unions, intersections, or primitive types. They are also helpful when you don't need the features of interfaces like
implements
orextends
. -
Generic Interfaces: Ideal for creating reusable structures that can work with a variety of types, especially in scenarios where the type is not known upfront (e.g., API responses).
-
Union Types (Type Aliases): Best for creating a type that can represent one of several possible values, often used for status codes, option types, etc.
Example Scenario:
If you are designing a TypeScript project that involves a lot of object structures, especially those that might be extended or implemented by different classes, interfaces would be the way to go.
However, if you need to handle API responses where the data can be of various types, using a generic interface would be more suitable. For something like an HTTP status that can be "success" | "error" | "loading"
, a type alias with a union type would be the most appropriate.
Each has its place, and choosing the right one depends on the specific needs of your project.