Explain the difference between `type` and `interface`. When would you choose one over the other?
3 minadvancedtypescriptdifferencetypeinterfacechoose
Quick Answer
Both type and interface are used to define object shapes in TypeScript, but they have important differences.
Detailed Answer
Explain the difference between type and interface. When would you choose one over the other?
Answer:
Both type and interface are used to define object shapes in TypeScript, but they have important differences:
Key Differences:
- Declaration Merging:
// Interface - supports declaration merging
interface User {
name: string;
}
interface User {
age: number;
}
// Result: User has both name and age
const user: User = { name: 'John', age: 30 };
// Type - does NOT support declaration merging
type UserType = {
name: string;
}
// This would cause an error
type UserType = {
age: number;
}
- Extensibility:
// Interface - uses 'extends'
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// Type - uses intersection (&)
type AnimalType = {
name: string;
}
type DogType = AnimalType & {
breed: string;
}
- Union Types:
// Type - supports union types
type Status = 'loading' | 'success' | 'error';
// Interface - cannot represent union types directly
interface StatusInterface {
// Cannot represent 'loading' | 'success' | 'error'
}
- Computed Properties:
// Type - supports computed/mapped properties
type Keys = 'name' | 'age';
type User = {
[K in Keys]: string;
}
// Interface - limited support for computed properties
interface UserInterface {
[key: string]: any; // Only index signatures
}
- Primitive Types:
// Type - can alias primitive types
type ID = string | number;
type Status = 'active' | 'inactive';
// Interface - cannot alias primitives
interface IDInterface = string; // Error!
When to Use Each:
Use interface when:
- Defining object shapes that might be extended
- Working with classes (implements)
- You need declaration merging
- Creating public APIs that others might extend
// Good for interfaces
interface ApiResponse {
data: any;
status: number;
}
interface UserResponse extends ApiResponse {
data: User;
}
class UserService implements UserResponse {
data: User;
status: number;
}
Use type when:
- Creating union types
- Aliasing primitive types
- Creating complex mapped types
- You need computed properties
- Creating utility types
// Good for types
type Theme = 'light' | 'dark';
type EventHandler<T> = (event: T) => void;
type Partial<T> = {
[P in keyof T]?: T[P];
}
// Complex utility type
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
}
Performance Considerations:
- Interfaces are slightly faster to compile
- Types can be more memory intensive for complex unions
- Both are erased at runtime (no performance difference)
Best Practices:
- Use
interfacefor object shapes that represent contracts - Use
typefor unions, primitives, and complex transformations - Be consistent within your codebase
- Prefer
interfacefor public APIs - Use
typefor internal utilities and transformations