Type guard là gì?

Noun None

Trong TypeScript, type guard sử dụng một số toán tử (operator) được tích hợp sẵn (built-in) như typeof, instanceof và in. Nó được sử dụng để xác định xem một đối tượng có chứa thuộc tính (attribute) hay không, xác định xem một giá trị có phải là một thể hiện (instance) của một lớp (class) không, xác định kiểu dữ liệu của một biến, nhận một kiểu dữ liệu và cho TypeScript biết nếu nó có thể được thu hẹp (narrow) thành một cái gì đó cụ thể hơn..

Có 4 cách chính để sử dụng (type guard):

  • Instanceof type guard
  • Typeof type guard
  • In type guard
  • Equality narrowing type guard

Instanceof type guard

instanceof là một type guard tích hợp sẵn có thể được sử dụng để kiểm tra xem một giá trị có phải là một thể hiện của một hàm khởi tạo (constructor function) hoặc lớp nhất định hay không. Với type guard này, chúng ta có thể kiểm tra xem một đối tượng (object) hoặc giá trị có được dẫn xuất từ ​​một lớp hay không, điều này rất hữu ích để xác định kiểu dữ liệu của một kiểu thể hiện (instance type).

objectVariable instanceof ClassName;

Trong ví dụ dưới đây, chúng ta thấy một ví dụ về instanceof


interface Accessory {
    brand: string;
  }
  class Necklace implements Accessory{
    kind: string;
    brand: string;
    constructor(brand: string, kind: string) {    
      this.brand = brand;
      this.kind = kind;
    }
  }
  class bracelet implements Accessory{
    brand: string;
    year: number;
    constructor(brand: string, year: number) {    
      this.brand = brand;
      this.year = year;
    }
  }
  const getRandomAccessory = () =>{
    return Math.random() 

Hàm getRandomAccessory ở trên trả về đối tượng Necklace hoặc bracelet, vì cả hai đều triển khai (implement) interface Accessory. Các signature của hàm tạo (constructor) cho cả Necklace và bracelet đều khác nhau và instanceof so sánh cả hai signature của hàm tạo để xác định kiểu dữ liệu một cách hiệu quả.

Typeof type guard

typeof được sử dụng để xác định kiểu dữ liệu của một biến. typeof được cho là rất hạn chế vì nó chỉ có thể xác định các kiểu dữ liệu sau được JavaScript công nhận: boolean, string, bigint, symbol, undefined, function, number.

Đối với bất kỳ thứ gì bên ngoài danh sách này, typeof chỉ đơn giản trả về đối tượng.

typeof có thể được viết theo hai cách sau:


typeof v !== "typename"
#or 
typeof v === "typename"

typename có thể là một chuỗi, số, ký hiệu (symbol) hoặc boolean.

Trong ví dụ dưới đây, StudentId có một kiểu dữ liệu union (union type) string | number. Chúng ta thấy rằng nếu biến là một chuỗi, Student được in, và nếu là một số Id được in. typeof giúp chúng ta trích xuất kiểu dữ liệu từ x:


function StudentId(x: string | number) {
    if (typeof x == 'string') {
        console.log('Student');
    }
    if (typeof x === 'number') {
        console.log('Id');
    }
}
StudentId(`446`); //prints Student
StudentId(446); //prints Id

In type guard

in kiểm tra xem một đối tượng có thuộc tính cụ thể hay không, sử dụng thuộc tính đó để phân biệt giữa các kiểu dữ liệu khác nhau. Nó thường trả về một boolean, cho biết thuộc tính có tồn tại trong đối tượng đó hay không. Nó được sử dụng cho các tính năng narrowing của nó, cũng như để kiểm tra sự hỗ trợ của trình duyệt (browser support).

Cú pháp cơ bản cho in như sau:

propertyName in objectName

Trong ví dụ dưới đây, nin sẽ kiểm tra xem thuộc tính house có tồn tại hay không. Trong trường hợp nó tồn tại, thì trả về giá trị true boolean và nếu nó không tồn tại thì trả về false.


"house" in { name: "test", house: { parts: "door" } }; // => true
"house" in { name: "test", house: { parts: "windows" } }; // => true
"house" in { name: "test", house: { parts: "roof" } }; // => true
"house" in { name: "test" }; // => false
"house" in { name: "test", house: undefined }; // => true

Equality narrowing type guard

Equality narrowing kiểm tra giá trị của một biểu thức (expression). Để hai biến bằng nhau, cả hai biến phải cùng kiểu dữ liệu. Nếu kiểu dữ liệu của một biến không được biết, nhưng nó bằng với một biến khác có kiểu dữ liệu, thì Typescript sẽ thu hẹp kiểu dữ liệu của biến đầu tiên với thông tin mà biến đã biết cung cấp:


function getValues(a: number | string, b: string) {
    if(a === b) {
        // this is where the narrowing takes place. narrowed to string
        console.log(typeof a) // string
    } else {
        // if there is no narrowing, type remains unknown
        console.log(typeof a) // number or string
    }
}

Nếu biến a bằng biến b thì cả hai phải có cùng kiểu dữ liệu. Trong trường hợp này, Typecript sẽ thu hẹp nó thành chuỗi. Nếu không thu hẹp, kiểu của a vẫn chưa rõ ràng vì nó có thể là một số hoặc một chuỗi.

Learning English Everyday