Trong TypeScript, bạn có thể định nghĩa các hình dạng tùy chỉnh bằng cách sử dụng bí danh type
hoặc interface
. Nhưng khi phải lựa chọn giữa chúng, nhiều nhà phát triển hỏi: "Kiểu TypeScript so với Giao diện?" Câu trả lời ngày càng rõ ràng: sử dụngtype .
Mặc dù cả hai đều có điểm tương đồng, type
cung cấp tính linh hoạt hơn, hỗ trợ các mẫu phức tạp và phù hợp hơn với TypeScript và các framework hiện đại. Trong hướng dẫn này, bạn sẽ tìm hiểu sự khác biệt, điểm mạnh và lý do tại sao type
mặc định tốt hơn.
Kiểu dữ liệu và giao diện là gì?
Cả type
và interface
đều xác định hình dạng đối tượng hoặc chữ ký hàm:
// Using type
type Point = { x: number; y: number };
type SetPoint = (x: number, y: number) => void; // Using interface
interface Point { x: number; y: number }
interface SetPoint { (x: number, y: number): void }
Chúng trông và hoạt động tương tự nhau, nhưng sự khác biệt xuất hiện trong các trường hợp sử dụng nâng cao.
Tại sao Type lại chiến thắng trong TypeScript hiện đại?
Nhưng tại sao các loại lại được ưa chuộng hơn?
1- Biểu cảm hơn
type
linh hoạt hơn và có thể mô tả những thứ interface
không thể mô tả, như hợp nhất, nguyên hàm, bộ, kiểu ánh xạ và kiểu có điều kiện.
// Using `type` to alias primitive types.
// `interface` cannot be used with primitives like `string`, `number`, etc.
type Name = string; // Using `type` to define a union type.
// `interface` does not support union types directly.
type Result = { success: true } | { error: string }; // Using `type` to define a tuple.
// Tuples can't be defined using `interface`; `type` is required.
type Coordinates = [number, number]; // Using `type` with mapped types to create a read-only version of a given type.
// This utilizes TypeScript's advanced type system, which `type` handles more flexibly than `interface`.
type Readonly<T> = { readonly [K in keyof T]: T[K] }; // Conditional type (cannot be achieved using `interface`)
type ResponseData<T extends boolean> = T extends true ? { success: true; data: string } : { success: false; error: string }; // When the flag is true, the shape has 'data'
type SuccessResponse = ResponseData<true>; // { success: true; data: string } // When the flag is false, the shape has 'error'
type ErrorResponse = ResponseData<false>; // { success: false; error: string }
Giao diện không thể diễn đạt được những mẫu này.
2- An toàn hơn và dễ dự đoán hơn
Chỉ interface
hỗ trợ việc hợp nhất khai báo:
interface Config { debug: boolean }
interface Config { verbose: boolean }
// Becomes: { debug: boolean; verbose: boolean }
Điều này có thể hữu ích trong những trường hợp hiếm hoi nhưng lại rủi ro trong hầu hết các trường hợp — nó dẫn đến những bất ngờ khó gỡ lỗi. type
ngăn chặn việc định nghĩa lại một cách ngẫu nhiên.
3- Hoạt động ở mọi nơi
type
có thể mở rộng cả kiểu và giao diện, và bạn có thể sử dụng giao điểm ( &
) để biên soạn.
type A = { a: string };
type B = A & { b: number }; interface I { i: boolean }
type Combined = I & { x: number };
Điều này giúp type
cho các tình huống thực tế trở nên nhất quán hơn.
4- Lý tưởng cho các mẫu chức năng và phản ứng
Các thư viện và công cụ front-end hiện đại như React , Redux và Zod có xu hướng ưu tiên sử dụng bí danh type
do tính linh hoạt của chúng, đặc biệt là khi làm việc với các hợp nhất phân biệt , thuộc tính phức tạp hoặc các mẫu chức năng.
// Simple React props using a type alias
type Props = { children: React.ReactNode }; // Discriminated union for Redux-like actions
type Action = | { type: 'start' } | { type: 'stop' }; // This is a discriminated union: a union of object types
// that share a common `type` field used to determine the variant.
Bạn không thể định nghĩa các kiểu hợp nhất hoặc các thuộc tính phức tạp một cách rõ ràng bằng interface
.
Khi giao diện có ý nghĩa
Mặc dù type
nhìn chung linh hoạt hơn nhưng interface
vẫn đóng vai trò quan trọng trong một số trường hợp nhất định:
- API/Thư viện công khai –
interface
hỗ trợ hợp nhất khai báo , cho phép mở rộng hoặc tăng cường thư viện một cách an toàn. - Các mẫu OOP trong đó các lớp thực hiện hợp đồng
interface IUser { id: string; login(): void;
} class Admin implements IUser { id = 'admin'; login() {}
}
Nhưng ngay cả ở đây, bạn vẫn có thể sử dụng type
thay thế.
type IUser = { id: string; login(): void;
} class Admin implements IUser { id = 'admin'; login() {}
}
Mặc dù cả hai phiên bản đều hoạt động, nhưng phiên bản interface
này có xu hướng được ưa chuộng hơn trong các cơ sở mã nặng về OOP vì tính rõ ràng về mặt ngữ nghĩa và hỗ trợ mở rộng thông qua extends
hoặc hợp nhất khai báo.
Phần kết luận
Trong hầu hết các cơ sở mã TypeScript thực tế, type
nó vượt trội hơn interface
. Nó xử lý mọi thứ từ hợp nhất đến bộ, hỗ trợ các kiểu ánh xạ và có điều kiện, và tránh các hành vi không mong muốn như hợp nhất khai báo.
Cuối cùng, trừ khi bạn đang triển khai API theo phong cách OOP công khai hoặc cần hợp nhất khai báo, hãy sử dụng type
.