TypeScript Type vs Interface
Understanding the differences and when to use each
⚖️ Type vs Interface
Both types and interfaces define object shapes in TypeScript, but they have key differences. Interfaces are extendable and better for object-oriented patterns, while types are more flexible for unions, primitives, and complex compositions.
// Interface
interface User {
name: string;
}
// Type
type Person = {
name: string;
};
Key Differences
Extension
How they extend
// Interface
interface A extends B {}
// Type
type A = B & C;
Union Types
Only types support unions
// Type only
type ID =
string | number;
Declaration Merging
Only interfaces merge
// Interface merges
interface User {
name: string;
}
interface User {
age: number;
}
Primitives
Only types alias primitives
// Type only
type Name = string;
type Count = number;
🔹 Similarities
Both can define object shapes:
// Using Interface
interface UserInterface {
name: string;
age: number;
}
// Using Type
type UserType = {
name: string;
age: number;
};
let user1: UserInterface = { name: "Alice", age: 25 };
let user2: UserType = { name: "Bob", age: 30 };
console.log(user1.name);
console.log(user2.name);
Output:
Alice
Bob
🔹 Interface Extension
Interfaces use the extends keyword:
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
let myDog: Dog = {
name: "Buddy",
breed: "Labrador"
};
console.log(`${myDog.name} is a ${myDog.breed}`);
Output:
Buddy is a Labrador
🔹 Type Intersection
Types use the & operator to combine:
type Animal = {
name: string;
};
type Pet = {
owner: string;
};
type DomesticAnimal = Animal & Pet;
let myCat: DomesticAnimal = {
name: "Whiskers",
owner: "Alice"
};
console.log(`${myCat.name} belongs to ${myCat.owner}`);
Output:
Whiskers belongs to Alice
🔹 Union Types (Type Only)
Only types can create unions:
type Status = "success" | "error" | "pending";
type ID = string | number;
let currentStatus: Status = "success";
let userId: ID = 123;
let productId: ID = "prod_456";
console.log(`Status: ${currentStatus}`);
console.log(`User ID: ${userId}`);
console.log(`Product ID: ${productId}`);
Output:
Status: success
User ID: 123
Product ID: prod_456
🔹 Declaration Merging (Interface Only)
Interfaces with the same name automatically merge:
interface Window {
title: string;
}
interface Window {
width: number;
}
// Both properties are now available
let myWindow: Window = {
title: "My App",
width: 800
};
console.log(`${myWindow.title} - Width: ${myWindow.width}px`);
Output:
My App - Width: 800px
Note: Types cannot be merged. Declaring the same type twice causes an error.
🔹 Primitive Aliases (Type Only)
Only types can alias primitive values:
type Username = string;
type Age = number;
type IsActive = boolean;
let user: Username = "john_doe";
let userAge: Age = 28;
let active: IsActive = true;
console.log(`User: ${user}, Age: ${userAge}, Active: ${active}`);
Output:
User: john_doe, Age: 28, Active: true
🔹 Tuple Types (Type Only)
Types work better with tuples:
type Point = [number, number];
type RGB = [number, number, number];
let coordinate: Point = [10, 20];
let color: RGB = [255, 128, 0];
console.log(`Point: (${coordinate[0]}, ${coordinate[1]})`);
console.log(`Color: rgb(${color.join(", ")})`);
Output:
Point: (10, 20)
Color: rgb(255, 128, 0)
🔹 When to Use Each
Use Interface When:
- Defining object shapes and contracts
- Working with classes and OOP patterns
- You need declaration merging
- Building public APIs or libraries
- Extending other interfaces
Use Type When:
- Creating union or intersection types
- Aliasing primitives or tuples
- Using mapped or conditional types
- Defining complex type compositions
- Working with utility types
🔹 Practical Comparison
Real-world example showing both:
// Interface for object structure
interface Product {
id: number;
name: string;
price: number;
}
// Type for union and complex types
type PaymentMethod = "credit" | "debit" | "paypal";
type OrderStatus = "pending" | "shipped" | "delivered";
// Combining both
interface Order {
product: Product;
payment: PaymentMethod;
status: OrderStatus;
}
let myOrder: Order = {
product: { id: 1, name: "Laptop", price: 999 },
payment: "credit",
status: "pending"
};
console.log(`Order: ${myOrder.product.name} - ${myOrder.status}`);
Output:
Order: Laptop - pending