# TypeScript - Tương thích Loại
Xin chào các pháp sư lập trình tương lai! Hôm nay, chúng ta sẽ bắt đầu một hành trình thú vị vào thế giới của TypeScript và khám phá khái niệm fascinating về Tương thích Loại. Đừng lo lắng nếu bạn là người mới bắt đầu lập trình - Tôi sẽ là hướng dẫn viên thân thiện của bạn, và chúng ta sẽ cùng nhau giải quyết chủ đề này từng bước một. Vậy, hãy lấy键盘 (keyboards) ảo của bạn và cùng nhau thực hiện một số phép thuật TypeScript!
## TypeScript Kiểm tra Tương thích Loại Như Thế Nào?
Hãy tưởng tượng bạn đang cố gắng phù hợp các khối hình khác nhau vào một lỗ. Tương thích loại của TypeScript hơi giống như vậy - nó là về việc một loại có thể phù hợp vào một loại khác. Nhưng thay vì các hình dạng vật lý, chúng ta đang làm việc với các loại dữ liệu.
### Kiểu Structural
TypeScript sử dụng cái gọi là "kiểu structural". Điều này có nghĩa là nó quan tâm hơn đến hình dạng của một đối tượng而不是 tên loại chính xác. Hãy xem một ví dụ:
```typescript
interface Pet {
name: string;
}
class Dog {
name: string;
}
let pet: Pet;
let dog = new Dog();
pet = dog; // Điều này là okay!
Trong này vườn ma thuật, TypeScript nói, "Hey, cả Pet
và Dog
đều có thuộc tính name
kiểu string. Chúng trông alike với tôi, vì vậy chúng tương thích!" Điều này giống như nói một đinh vuông phù hợp vào một lỗ vuông, ngay cả khi một cái được gọi là "square" và cái khác là "block".
Kiểu Duck
Có một cụm từ thú vị trong lập trình: "Nếu nó đi như một con vịt và kêu như một con vịt, thì nó phải là một con vịt." Đây là essence của kiểu duck, và TypeScript chấp nhận triết lý này. Hãy xem nó trong hành động:
interface Quacker {
quack(): void;
}
class Duck {
quack() {
console.log("Quack!");
}
}
class Person {
quack() {
console.log("Tôi đang bắt chước một con vịt!");
}
}
let quacker: Quacker = new Duck(); // Đương nhiên là okay
quacker = new Person(); // Điều này cũng ổn!
TypeScript không quan tâm rằng Person
không được khai báo rõ ràng là Quacker
. Nó chỉ quan tâm rằng Person
có phương thức quack
, giống như Quacker
làm. Vì vậy, cả Duck
và Person
đều tương thích với Quacker
.
Làm Thế Nào Để Sử Dụng Tương Thích Loại Hiệu Quả?
Sử dụng tương thích loại hiệu quả giống như việc giải một puzzle giỏi. Dưới đây là một số lời khuyên:
1. Hiểu Kiểm Tra Literal Object
TypeScript nghiêm ngặt hơn với các literal object. Hãy xem tại sao:
interface Point {
x: number;
y: number;
}
let p: Point;
// Điều này là okay
p = { x: 10, y: 20 };
// Điều này sẽ gây ra lỗi
p = { x: 10, y: 20, z: 30 };
TypeScript nói, "Whoa there! Tôi yêu cầu một Point
, nhưng bạn lại đưa tôi cái gì đó extra (z
). Điều đó không được phép!" Điều này giúp bắt lỗi tiềm ẩn nơi bạn có thể sử dụng một đối tượng sai cách.
2. Sử Dụng Các Thuộc Tính Tùy Chọn
Đôi khi, bạn muốn linh hoạt hơn. Đó là khi các thuộc tính tùy chọn rất hữu ích:
interface Options {
color?: string;
width?: number;
}
function configure(options: Options) {
// ...
}
configure({ color: "red" }); // Okay
configure({ width: 100 }); // Okay
configure({}); // Cũng okay!
Bằng cách làm cho các thuộc tính tùy chọn (với dấu ?
), bạn đang nói với TypeScript, "It's cool if these aren't always there."
Hàm và Tương Thích Loại
Hàm giống như những cây dao đa năng của lập trình - chúng rất linh hoạt. Hãy xem tương thích loại hoạt động như thế nào với chúng:
Tương Thích Tham Số
TypeScript rất khoan dung với các tham số hàm:
let x = (a: number) => 0;
let y = (b: number, s: string) => 0;
y = x; // Okay
x = y; // Lỗi
Điều này có thể看起来 counterintuitive, nhưng nó là an toàn. TypeScript nói, "Nếu bạn đang mong đợi một hàm có hai tham số, thì việc cho nó một hàm có ít hơn là okay. Tham số extra sẽ chỉ bị bỏ qua."
Tương Thích Kiểu Trả Về
Kiểu trả về cũng cần phải tương thích:
let x = () => ({name: "Alice"});
let y = () => ({name: "Alice", location: "Wonderland"});
x = y; // Okay
y = x; // Lỗi
Được phép trả về nhiều hơn dự kiến, nhưng không ít hơn. Điều này giống như khi bạn đặt hàng một pizza và nhận được thêm topping miễn phí - điều đó là okay! Nhưng nếu bạn đặt hàng một pizza với topping và chỉ nhận được vỏ, bạn sẽ thất vọng.
Lớp và Tương Thích Loại
Lớp giống như những bản vẽ cho các đối tượng, và chúng tuân theo các quy tắc tương thích alike:
class Animal {
feet: number;
constructor(name: string, numFeet: number) { }
}
class Size {
feet: number;
}
let a: Animal;
let s: Size;
a = s; // Okay
s = a; // Okay
TypeScript chỉ quan tâm đến các thành viên instance. Nó nói, "Cả hai đều có thuộc tính feet
? Tốt đủ cho tôi!"
Thành Viên Private và Protected
Tuy nhiên, khi các lớp có thành viên private hoặc protected, mọi thứ trở nên nghiêm ngặt hơn:
class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}
class Rhino extends Animal {
constructor() { super("Rhino"); }
}
class Employee {
private name: string;
constructor(theName: string) { this.name = theName; }
}
let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");
animal = rhino; // Okay
animal = employee; // Lỗi: 'Animal' và 'Employee' không tương thích
Dù Animal
và Employee
có vẻ alike, TypeScript coi chúng khác nhau vì các thành viên private
của chúng đến từ các khai báo khác nhau.
Kết Luận
Và thế là bạn đã có, các học trò lập trình của tôi! Chúng ta đã cùng nhau hành trình qua vùng đất của TypeScript's type compatibility. Nhớ rằng, TypeScript ở đây để giúp bạn viết mã tốt hơn, an toàn hơn. Nó giống như một pháp sư thân thiện đang nhìn chừng bạn, nhẹ nhàng gợi ý khi bạn sắp mắc lỗi.
Tiếp tục thực hành, tiếp tục thử nghiệm, và sớm bạn sẽ casting TypeScript spells như một pro! Hẹn gặp lại các bạn, chúc các bạn lập trình vui vẻ!
Credits: Image by storyset