value instanceof SomeClass là một phép kiểm tra của JavaScript chạy lúc runtime: nó là true khi SomeClass.prototype nằm trong prototype chain của object, nghĩa là object được tạo bằng new SomeClass (hoặc một lớp con). TypeScript thu hẹp value về SomeClass bên trong phép kiểm tra.
Dùng instanceof cho object được tạo từ lớp, và typeof cho giá trị nguyên thủy. Ở đây cần cả hai: instanceof tách riêng Date, rồi typeof chia phần còn lại.
Thu hẹp kiểu với lớp của bạn
instanceof thu hẹp về lớp đó ở nhánh true và loại nó ra ở nhánh false, nên một union gồm nhiều lớp có thể được xử lý lần lượt từng thành phần.
Instance của lớp con cũng vượt qua phép kiểm tra với lớp cha: nếu Square extends Rect thì new Square(2) instanceof Rect là true. Khi các nhánh xử lý khác nhau, hãy kiểm tra lớp cụ thể nhất trước.
Lớp con của Error trong catch
Cách dùng instanceof phổ biến nhất là trong catch. Với strict, giá trị bắt được là unknown (thứ gì cũng có thể bị ném ra), và instanceof là cách để quay về một lỗi có kiểu.
Đầu ra:
404: /missing.txt
TypeError: path must be absolute
class X extends Error hoạt động với instanceof trên mọi target mà TypeScript 7 hỗ trợ (ES2015 trở lên). Lời khuyên cũ về việc gọi Object.setPrototypeOf(this, X.prototype) trong hàm khởi tạo chỉ áp dụng cho code biên dịch sang ES5, một target mà TypeScript 7 đã bỏ.
instanceof không dùng được với interface hay type
Interface và type alias chỉ tồn tại cho trình biên dịch. Sau khi biên dịch, không còn giá trị User nào để so sánh, nên TypeScript từ chối phép kiểm tra:
Trình biên dịch báo index.ts(8,24): error TS2693: 'User' only refers to a type, but is being used as a value here. Có hai cách sửa. Tự kiểm tra hình dạng bằng một type guard, tức một hàm trả về value is User:
Hoặc, nếu code của bạn tự tạo các object này, hãy biến User thành lớp và tạo chúng bằng new; khi đó instanceof hoạt động. Trang type guard nói chi tiết về predicate và assertion function.
Đúng kiểu chưa chắc đúng instance
TypeScript so sánh kiểu theo cấu trúc: một object literal có cùng các thành viên với một lớp sẽ gán được cho kiểu lớp đó. instanceof không nhìn vào cấu trúc. Nó đi dọc prototype chain, và một object chưa từng được tạo bằng new sẽ không qua được phép kiểm tra, kể cả khi trình biên dịch chấp nhận nó là kiểu đó.
Dòng cuối là điểm quan trọng. structuredClone, JSON.parse(JSON.stringify(...)) và message giữa các worker đều trả về object thuần không có prototype của lớp, dù kiểu tĩnh của chúng vẫn có thể ghi là Point. Khi instance của lớp đi qua những ranh giới như vậy, hãy dựng lại chúng (new Point(copy.x, copy.y)) trước khi dựa vào instanceof hay các phương thức.
instanceof và giá trị nguyên thủy
Giá trị nguyên thủy (string, number, boolean...) không phải object và không có prototype chain, nên "hi" instanceof String là false. TypeScript báo lỗi này khi có thể: với một giá trị kiểu string ở vế trái, instanceof là lỗi TS2358, The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. Với giá trị nguyên thủy, hãy dùng typeof.
| Giá trị | Phép kiểm tra instanceof | Kết quả |
|---|---|---|
new Date() | instanceof Date | true |
[1, 2] | instanceof Array | true (nhưng nên dùng Array.isArray) |
new TypeError("x") | instanceof Error | true (lớp con) |
{ x: 1, y: 2 } | instanceof Point | false (chưa từng được tạo bằng new) |
Object.create(null) | instanceof Object | false (không có prototype) |
"hi" | instanceof String | false (giá trị nguyên thủy) |
Giá trị từ realm khác
instanceof so sánh với một đối tượng hàm khởi tạo cụ thể. Code chạy trong một realm khác (một iframe, hoặc một context vm của Node) có Array, Error và Date riêng, nên một mảng được tạo ở đó sẽ không qua được instanceof Array ở đây. Điều tương tự xảy ra khi hai bản sao của cùng một package npm cùng nằm trong node_modules: mỗi bản có lớp riêng, và instance từ bản này không qua được instanceof với bản kia. Với mảng, Array.isArray hoạt động xuyên realm. Với kiểu của riêng bạn, kiểm tra một thuộc tính (một type guard, hoặc một field kind) sẽ tránh được hoàn toàn vấn đề này.
Câu hỏi thường gặp
Làm sao kiểm tra một object có phải instance của một lớp trong TypeScript?
Dùng value instanceof ClassName. Đây là phép kiểm tra lúc chạy (JavaScript thuần), và TypeScript thu hẹp value về ClassName bên trong if. Nó dùng được với các lớp có sẵn như Date, Map và Error cũng như lớp của chính bạn.
Có dùng instanceof với interface trong TypeScript được không?
Không. Interface và type alias bị xóa khi TypeScript biên dịch sang JavaScript, nên lúc chạy không còn gì để so sánh. x instanceof User với User là một interface sẽ gây lỗi TS2693, "'User' only refers to a type, but is being used as a value here." Thay vào đó, hãy kiểm tra các thuộc tính bằng một hàm type guard, hoặc biến User thành lớp nếu bạn tự tạo các object đó.
Vì sao instanceof trả về false với một object đúng kiểu?
Kiểu trong TypeScript mang tính cấu trúc: object literal { x: 1, y: 2 } gán được cho kiểu lớp Point nếu có cùng các thành viên. Nhưng instanceof kiểm tra prototype chain, mà literal đó chưa bao giờ được tạo bằng new Point, nên kết quả là false. Điều tương tự xảy ra với instance của lớp đã đi qua JSON, structuredClone hoặc một kênh message, vì chúng quay về dưới dạng object thuần.
instanceof có hoạt động với lớp Error tự định nghĩa trong TypeScript không?
Có, với mọi target hiện đại. class NotFound extends Error {} rồi err instanceof NotFound là true. Vấn đề cũ khi nó trả về false chỉ ảnh hưởng tới code biên dịch sang ES5, và TypeScript 7 không còn hỗ trợ target ES5.
Vì sao "hello" instanceof String lại là false?
Một chuỗi literal là giá trị nguyên thủy, không phải object, nên không có prototype chain để kiểm tra. instanceof String chỉ đúng với object bao được tạo bằng new String(). TypeScript từ chối instanceof trên một giá trị có kiểu string (TS2358); với giá trị nguyên thủy, hãy dùng typeof value === "string".