# TypeScript - Type Guards: A Beginner's Guide

Xin chào bạn, tương lai của ngôi sao lập trình! ? Tôi rất vui mừng được làm hướng dẫn viên của bạn trong hành trình thú vị vào thế giới của TypeScript và Type Guards. Là một ai đó đã dạy khoa học máy tính trong nhiều năm, tôi có thể告诉 bạn rằng việc hiểu type guards giống như có một siêu năng lực trong vũ trụ TypeScript. Vậy hãy cùng nhau lặn sâu và mở khóa sức mạnh này nhé!

## What are Type Guards?

Trước khi chúng ta nhảy vào chi tiết, hãy hiểu type guards là gì. Hãy tưởng tượng bạn là một bảo vệ an ninh tại một buổi tiệc sang trọng. Công việc của bạn là kiểm tra vé mời của mỗi khách và đảm bảo họ được phép vào đúng khu vực. Type guards trong TypeScript làm công việc tương tự - chúng giúp trình biên dịch kiểm tra và thu hẹp 类型 của một biến trong một khối mã nhất định.

Bây giờ, hãy cùng khám phá ba loại guard chính mà chúng ta sẽ học hôm nay:

| Type Guard | Mô tả |
|------------|-------------|
| typeof | Kiểm tra 类型 của một biến |
| in | Kiểm tra xem một thuộc tính có tồn tại trong một đối tượng hay không |
| instanceof | Kiểm tra xem một đối tượng có phải là một thể hiện của một lớp hay không |

## The 'typeof' Type Guard in TypeScript

Type guard 'typeof' giống như hỏi, "Bạn là loại gì?" Nó được sử dụng để kiểm tra 类型 của một biến. Hãy xem một ví dụ:

```typescript
function printAll(strs: string | string[] | null) {
  if (typeof strs === "object") {
    for (const s of strs) {
      console.log(s);
    }
  } else if (typeof strs === "string") {
    console.log(strs);
  } else {
    // không làm gì
  }
}

Trong ví dụ này, chúng ta sử dụng typeof để kiểm tra xem strs có phải là một đối tượng (bao gồm cả mảng) hay một chuỗi. Nếu nó là một đối tượng, chúng ta duyệt qua nó. Nếu nó là một chuỗi, chúng ta in nó trực tiếp.

TypeScript - Type Guards

Đây là một cách thú vị để nhớ: tưởng tượng bạn đang ở một cửa hàng thú cưng, và bạn muốn biết một con vật có phải là chó hay mèo hay không. Bạn có thể hỏi, "Bạn là loại động vật gì?" Đó chính xác là điều typeof làm trong TypeScript!

The 'in' Type Guard in TypeScript

Type guard 'in' giống như hỏi, "Bạn có tính năng này không?" Nó kiểm tra xem một thuộc tính có tồn tại trong một đối tượng hay không. Hãy xem một ví dụ:

type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

Trong đoạn mã này, chúng ta kiểm tra xem animal có thuộc tính swim hay không. Nếu có, chúng ta giả định nó là một Fish và gọi phương thức swim. Nếu không, chúng ta giả định nó là một Bird và gọi phương thức fly.

Hãy tưởng tượng như này: nếu bạn đang cố gắng xác định thú cưng mới của bạn là cá hay chim, bạn có thể kiểm tra xem nó có vây hay không. Đó chính xác là điều type guard 'in' làm - nó kiểm tra một thuộc tính đặc trưng.

The 'instanceof' Type Guard in TypeScript

Type guard 'instanceof' giống như hỏi, "Bạn có phải là thành viên của gia đình này không?" Nó kiểm tra xem một đối tượng có phải là một thể hiện của một lớp cụ thể hay không. Dưới đây là một ví dụ:

class Bird {
  fly() {
    console.log("Bay...");
  }
}

class Fish {
  swim() {
    console.log("Bơi...");
  }
}

function move(pet: Bird | Fish) {
  if (pet instanceof Bird) {
    pet.fly();
  } else {
    pet.swim();
  }
}

let myBird = new Bird();
move(myBird); // Output: Bay...

Trong ví dụ này, chúng ta kiểm tra xem pet có phải là một thể hiện của lớp Bird hay không. Nếu có, chúng ta gọi phương thức fly. Nếu không, chúng ta giả định nó là Fish và gọi phương thức swim.

Hãy tưởng tượng bạn đang tham gia một buổi họp gia đình, và bạn đang cố gắng xác định ai là thành viên của gia đình Johnson. Bạn có thể hỏi, "Bạn có phải là Johnson không?" Đó chính xác là điều instanceof làm trong TypeScript!

Putting It All Together

Bây giờ chúng ta đã học về ba type guard này, hãy cùng xem cách chúng ta có thể sử dụng chúng cùng nhau:

class Car {
  drive() { console.log("Vroom!"); }
}

class Bicycle {
  ride() { console.log("Đạp xe!"); }
}

type Vehicle = Car | Bicycle | string;

function useVehicle(vehicle: Vehicle) {
  if (typeof vehicle === "string") {
    console.log(`Phương tiện là: ${vehicle}`);
  } else if (vehicle instanceof Car) {
    vehicle.drive();
  } else if ("ride" in vehicle) {
    vehicle.ride();
  } else {
    console.log("Loại phương tiện không rõ");
  }
}

useVehicle("Skateboard");  // Output: Phương tiện là: Skateboard
useVehicle(new Car());     // Output: Vroom!
useVehicle(new Bicycle()); // Output: Đạp xe!

Trong ví dụ này, chúng ta sử dụng tất cả ba type guard:

  1. Chúng ta sử dụng typeof để kiểm tra xem phương tiện có phải là chuỗi hay không.
  2. Chúng ta sử dụng instanceof để kiểm tra xem nó có phải là Car hay không.
  3. Chúng ta sử dụng in để kiểm tra xem nó có phương thức ride hay không (điều này có nghĩa là nó là Bicycle).

Đây giống như một siêu侦探, sử dụng tất cả kỹ năng của bạn để xác định chính xác loại phương tiện bạn đang đối mặt!

Conclusion

Và thế là bạn đã có nó, 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 Type Guards, khám phá typeof, in, và instanceof guards. Những công cụ mạnh mẽ này sẽ giúp bạn viết mã an toàn hơn, dự đoán hơn bằng cách cho TypeScript hiểu rõ hơn về ý định của bạn.

Nhớ rằng, sử dụng type guards giống như có một cuộc trò chuyện thân thiện với mã của bạn. Bạn đang đơn giản hỏi nó những câu hỏi để hiểu rõ hơn. Vậy lần sau khi bạn đang lập trình, đừng ngần ngại - hãy bắt đầu một cuộc trò chuyện với các biến của bạn bằng cách sử dụng các type guard này!

Tiếp tục luyện tập, 保持好奇心, và trước khi bạn nhận ra, bạn sẽ trở thành một chuyên gia trong việc bảo vệ type. Đến gặp lại lần sau, chúc bạn lập trình vui vẻ! ??

Credits: Image by storyset