Structural typing là một khái niệm quan trọng trong TypeScript, cho phép xác định kiểu dữ liệu dựa trên cấu trúc của nó thay vì tên của nó. Điều này có nghĩa là hai kiểu dữ liệu được coi là tương đương nếu chúng có cùng cấu trúc, cho phép TypeScript kiểm tra tính tương thích của các loại mà không cần dựa vào tên của chúng. Trong bài viết này, chúng ta sẽ khám phá cấu trúc của structural typing, cách hoạt động và các ví dụ minh họa.
Cách Hoạt Động của Structural Typing
Trong TypeScript, các kiểu dữ liệu được xác định không chỉ bởi tên của chúng mà còn bởi các thuộc tính và phương thức mà chúng có. Nếu hai kiểu có cùng một cấu trúc (tức là, các thuộc tính và kiểu dữ liệu của chúng phù hợp), TypeScript sẽ coi chúng là tương đương.
Ví dụ Cơ Bản
interface Person {
name: string;
age: number;
}
function greet(person: Person) {
console.log(`Hello, ${person.name}. You are ${person.age} years old.`);
}
const user = { name: "Alice", age: 25, location: "Wonderland" };
greet(user); // Kết quả: Hello, Alice. You are 25 years old.
Trong ví dụ trên, hàm greet
nhận vào một tham số có kiểu là Person
. Mặc dù user
có thêm thuộc tính location
, TypeScript vẫn cho phép truyền đối tượng này vào hàm greet
vì nó có đủ các thuộc tính cần thiết (name
và age
).
Tính Tương Thích của Các Kiểu
Tính Tương Thích Dựa Trên Cấu Trúc
Structural typing cho phép tính tương thích giữa các kiểu mà không cần phải khai báo chúng như là con của một lớp hay giao diện. Điều này giúp cho việc sử dụng các kiểu dữ liệu trở nên linh hoạt hơn.
Ví dụ Về Tính Tương Thích
interface Vehicle {
wheels: number;
drive(): void;
}
const car = {
wheels: 4,
drive() {
console.log("Driving a car!");
}
};
function useVehicle(vehicle: Vehicle) {
console.log(`This vehicle has ${vehicle.wheels} wheels.`);
vehicle.drive();
}
useVehicle(car); // Kết quả: This vehicle has 4 wheels. Driving a car!
Trong ví dụ này, đối tượng car
có cùng cấu trúc với Vehicle
, vì vậy nó có thể được truyền vào hàm useVehicle
mà không gặp lỗi.
Tính Kín Đáo và Kế Thừa
Tính Kín Đáo
Structural typing hỗ trợ tính kín đáo, nghĩa là bạn có thể xác định các kiểu mà không cần phải định nghĩa chúng trước đó.
function logCoordinates(point: { x: number; y: number }) {
console.log(`X: ${point.x}, Y: ${point.y}`);
}
const coordinates = { x: 10, y: 20 };
logCoordinates(coordinates); // Kết quả: X: 10, Y: 20
Trong trường hợp này, bạn không cần phải tạo một giao diện cho điểm, chỉ cần định nghĩa một kiểu trong tham số của hàm là đủ.
Kế Thừa
Cấu trúc kiểu còn cho phép bạn kế thừa từ các kiểu khác mà không cần phải khai báo lại toàn bộ.
interface Employee {
id: number;
name: string;
}
interface Manager extends Employee {
department: string;
}
const manager: Manager = {
id: 1,
name: "Bob",
department: "Sales"
};
function showManager(manager: Manager) {
console.log(`${manager.name} is the manager of ${manager.department}`);
}
showManager(manager); // Kết quả: Bob is the manager of Sales
Trong ví dụ này, Manager
kế thừa từ Employee
, và bạn có thể sử dụng Manager
như là một kiểu cho hàm showManager
.
Kết Luận
Structural typing trong TypeScript mang đến một cách tiếp cận linh hoạt để xác định và kiểm tra các kiểu dữ liệu. Thay vì dựa vào tên lớp hoặc giao diện, TypeScript cho phép bạn sử dụng cấu trúc của các kiểu để xác định tính tương thích. Điều này không chỉ làm cho mã nguồn trở nên rõ ràng và dễ duy trì hơn mà còn giúp bạn linh hoạt hơn trong việc làm việc với các kiểu dữ liệu khác nhau.