Type vs Interface trong TypeScript: Khác nhau gì?
Khi mới học TypeScript, có một câu hỏi gần như ai cũng gặp:
"Dùng type hay interface? Cái nào đúng hơn?"
Câu trả lời ngắn: cả hai đều đúng, và trong nhiều trường hợp có thể hoán đổi nhau. Nhưng có những điểm khác biệt quan trọng cần biết để dùng đúng chỗ.
Interface trong TypeScript là gì?
interface User {
name: string;
age: number;
email?: string; // ? nghĩa là optional
}
const user: User = {
name: "Nguyễn Văn An",
age: 25
};
implements trong class
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal {
name = "Rex";
makeSound() {
console.log("Gâu gâu!");
}
}
Declaration Merging — chỉ interface mới có
interface User {
name: string;
age: number;
}
interface User {
email: string; // Khai báo thêm — TypeScript sẽ gộp lại
}
// Kết quả: User có đủ name, age, email
const user: User = {
name: "An",
age: 25,
email: "an@example.com"
};
Type Alias trong TypeScript là gì?
type User = {
name: string;
age: number;
};
// Union type — chỉ type mới làm được
type Status = "active" | "inactive" | "pending";
type ID = string | number;
let status: Status = "active";
// status = "deleted"; // Lỗi!
Intersection Type
type Admin = {
adminLevel: number;
permissions: string[];
};
type User = {
name: string;
email: string;
};
type AdminUser = User & Admin;
const admin: AdminUser = {
name: "An",
email: "an@admin.com",
adminLevel: 2,
permissions: ["read", "write", "delete"]
};
So sánh type vs interface
| Tính năng | interface | type |
|---|---|---|
| Định nghĩa object | ✅ | ✅ |
| Declaration merging | ✅ | ❌ |
| Union type | ❌ | ✅ |
| Intersection type | extends | & |
| class implements | ✅ | ✅ (chỉ object type) |
| Primitive alias | ❌ | ✅ |
| Mapped types | ❌ | ✅ |
| Tuple type | ❌ | ✅ |
Khi nào dùng interface? Khi nào dùng type?
Dùng interface khi:
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
interface Repository<T> {
findById(id: number): Promise<T>;
save(entity: T): Promise<T>;
delete(id: number): Promise<void>;
}
Dùng type khi:
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type UserId = string | number;
type ApiError = NetworkError | ValidationError | AuthError;
type EventHandler<T> = (event: T) => void;
type Coordinate = [number, number];
Best practice trong dự án thực tế
interface ButtonProps {
label: string;
onClick: () => void;
variant?: "primary" | "secondary" | "danger";
disabled?: boolean;
}
function Button({ label, onClick, variant = "primary", disabled = false }: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn-${variant}`}
>
{label}
</button>
);
}
TypeScript chính thức (2026) khuyến nghị: dùng interface cho object và class, dùng type cho union/intersection và primitive. Quan trọng nhất là thống nhất trong team.
Kết luận
Quy tắc đơn giản:
- Định nghĩa hình dạng object → dùng interface
- Union type, literal type, kiểu phức tạp → dùng type
- Cả hai đều được → tuân theo quy ước của team
Bạn có thể thử trực tiếp trên TypeScript Playground.
Muốn ôn lại TypeScript từ đầu? Xem bài TypeScript là gì? Tại sao nên học TypeScript năm 2026.