Type vs Interface in TypeScript
In TypeScript, both type
aliases and interface
declarations allow you to define custom types, yet they serve slightly different purposes and offer unique capabilities. This guide provides a detailed comparison along with practical examples to help you choose the best tool for your needs.
Overview
Type Alias
A type alias creates a new name for any type, whether it's a primitive, union, intersection, tuple, or object. Type aliases are particularly useful for modeling complex type compositions.
// Object type alias
type User = {
name: string;
age: number;
};
// Union type alias
type ID = string | number;
// Tuple type alias
type Point = [number, number];
Interface
An interface primarily describes the structure of an object. Interfaces are ideal when you anticipate that the structure may be extended or when you benefit from declaration merging in large codebases.
// Basic interface
interface User {
name: string;
age: number;
}
// Extending interfaces
interface Person {
name: string;
}
interface Employee extends Person {
role: string;
}
Tip: Use interface
when planning for extension or merging, and opt for type
aliases for unions, intersections, and other complex types.
Key Differences
1. Declaration Syntax
- Interface:
interface User { name: string; age: number; }
- Type Alias:
type User = { name: string; age: number; };
2. Extensibility
- Interface:
Interfaces support extending other interfaces using theextends
keyword, facilitating inheritance and code reuse.interface Person { name: string; } interface Employee extends Person { role: string; }
- Type Alias:
Type aliases can combine types using intersections (&
), although this approach is less intuitive for extending object structures.type Person = { name: string }; type Employee = Person & { role: string };
3. Declaration Merging
- Interface:
Interfaces can be declared multiple times, with subsequent declarations automatically merging into one.interface User { name: string; } interface User { age: number; } // The merged User interface now contains both 'name' and 'age'.
- Type Alias:
Type aliases do not support declaration merging. Attempting to redeclare a type alias with the same name results in an error.type User = { name: string }; // type User = { age: number }; // Error: Duplicate identifier 'User'
4. Use Cases and Limitations
Feature | Interface | Type Alias |
---|---|---|
Object Shapes | ✅ Ideal for defining object structures | ✅ Suitable for objects |
Extensibility | ✅ Supports extends and declaration merging | ✅ Supports intersections (& ) |
Complex Types | ❌ Limited to object-like structures | ✅ Can represent unions, intersections, tuples, etc. |
Declaration Merging | ✅ Automatically merges multiple declarations | ❌ Not supported |
- Interfaces: Prefer when defining objects that may be extended or merged.
- Type Aliases: Opt for when working with unions, intersections, or more complex type compositions.
Advanced Examples
Unions and Tuples with Type Aliases
Type aliases are exceptionally powerful when representing non-object types.
// Union of string and number
type StringOrNumber = string | number;
// Tuple representing a coordinate
type Coordinate = [number, number];
Function Signatures
Both interfaces and type aliases can define function types.
- Interface:
interface Greet { (name: string): string; }
- Type Alias:
type Greet = (name: string) => string;
Hybrid Types
Hybrid types combine function signatures with additional properties. Both approaches can achieve this.
- Interface:
interface Counter { (start: number): string; interval: number; reset(): void; }
- Type Alias:
type Counter = { (start: number): string; interval: number; reset(): void; };
Conclusion
Both interface
and type
aliases are fundamental tools in TypeScript:
- Interfaces excel at defining object shapes, supporting inheritance, and enabling declaration merging.
- Type Aliases offer flexibility for representing unions, intersections, tuples, and more complex type patterns.
Ultimately, the choice depends on your specific needs. Don't hesitate to mix both approaches to achieve robust and maintainable type definitions.
Happy coding in TypeScript!