value instanceof SomeClass это проверка JavaScript, которая выполняется во время работы программы: она истинна, когда SomeClass.prototype есть в цепочке прототипов объекта, то есть когда объект создан через new SomeClass (или подкласс). TypeScript сужает value до SomeClass внутри проверки.
Используйте instanceof для объектов, созданных из классов, и typeof для примитивов. Здесь нужны оба: instanceof отделяет Date, а затем typeof делит то, что осталось.
Сужение ваших собственных классов
instanceof сужает до класса в ветке true и убирает его в ветке false, поэтому объединение классов можно обрабатывать по одному члену за раз.
Экземпляр подкласса тоже проходит проверку на родительский класс: если Square extends Rect, то new Square(2) instanceof Rect равно true. Если ветки различаются, проверяйте самый конкретный класс первым.
Подклассы Error в catch
Чаще всего instanceof используют в catch. В режиме strict пойманное значение имеет тип unknown (бросить можно что угодно), и instanceof позволяет вернуться к типизированной ошибке.
Вывод:
404: /missing.txt
TypeError: path must be absolute
class X extends Error работает с instanceof на любом target, который поддерживает TypeScript 7 (ES2015 и новее). Старый совет вызывать Object.setPrototypeOf(this, X.prototype) в конструкторе относился к коду, скомпилированному в ES5, а этот target в TypeScript 7 удалён.
instanceof не работает с интерфейсами и типами
Интерфейсы и псевдонимы типов существуют только для компилятора. После компиляции значения User, с которым можно сравнить, нет, поэтому TypeScript отказывается выполнять проверку:
Компилятор сообщает index.ts(8,24): error TS2693: 'User' only refers to a type, but is being used as a value here. Исправить можно двумя способами. Проверить форму самостоятельно защитником типа, функцией, которая возвращает value is User:
Или, если эти объекты создаёт ваш код, сделать User классом и создавать объекты через new; тогда instanceof работает. Предикаты и функции утверждения подробно описаны на странице защитники типов.
Правильный тип ещё не правильный экземпляр
TypeScript сравнивает типы по структуре: объектный литерал с теми же членами, что и у класса, можно присвоить типу класса. instanceof на структуру не смотрит. Он проходит по цепочке прототипов, и объект, который никогда не создавался через new, не проходит проверку, даже если компилятор принимает его как этот тип.
Важна последняя строка. structuredClone, JSON.parse(JSON.stringify(...)) и сообщения между воркерами возвращают обычные объекты без прототипа класса, хотя их статический тип всё ещё может говорить Point. Когда экземпляры классов пересекают такую границу, пересоздайте их (new Point(copy.x, copy.y)), прежде чем полагаться на instanceof или методы.
instanceof и примитивы
Примитивы (string, number, boolean...) не являются объектами и не имеют цепочки прототипов, поэтому "hi" instanceof String равно false. TypeScript отмечает ошибку, когда может: если слева значение типа string, instanceof даёт ошибку TS2358, The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. Для примитивов используйте typeof.
| Значение | Проверка instanceof | Результат |
|---|---|---|
new Date() | instanceof Date | true |
[1, 2] | instanceof Array | true (но лучше Array.isArray) |
new TypeError("x") | instanceof Error | true (подкласс) |
{ x: 1, y: 2 } | instanceof Point | false (никогда не конструировался) |
Object.create(null) | instanceof Object | false (нет прототипа) |
"hi" | instanceof String | false (примитив) |
Значения из другого realm
instanceof сравнивает с одним конкретным объектом-конструктором. У кода, который выполняется в другом realm (iframe или контексте vm в Node), свои Array, Error и Date, поэтому массив, созданный там, не проходит здесь instanceof Array. То же случается, когда в node_modules оказываются две копии одного npm-пакета: у каждой копии свой класс, и экземпляр из одной не проходит instanceof против другой. Для массивов Array.isArray работает между realm. Для ваших собственных типов проверка свойства (защитник типа или поле kind) полностью снимает проблему.
Часто задаваемые вопросы
Как проверить, что объект является экземпляром класса, в TypeScript?
Используйте value instanceof ClassName. Это проверка во время выполнения (обычный JavaScript), и TypeScript сужает value до ClassName внутри if. Она работает как для встроенных классов вроде Date, Map и Error, так и для ваших собственных.
Можно ли использовать instanceof с интерфейсом в TypeScript?
Нет. Интерфейсы и псевдонимы типов стираются при компиляции TypeScript в JavaScript, поэтому во время выполнения сравнивать не с чем. x instanceof User с интерфейсом User даёт ошибку TS2693, «'User' only refers to a type, but is being used as a value here.» Вместо этого проверьте свойства функцией-защитником типа или сделайте User классом, если вы сами создаёте эти объекты.
Почему instanceof возвращает false для объекта правильного типа?
Типы TypeScript структурные: объектный литерал { x: 1, y: 2 } можно присвоить типу класса Point, если у него те же члены. Но instanceof проверяет цепочку прототипов, а литерал никогда не создавался через new Point, поэтому результат false. То же происходит с экземплярами классов, прошедшими через JSON, structuredClone или канал сообщений: они возвращаются обычными объектами.
Работает ли instanceof со своими классами ошибок в TypeScript?
Да, с любым современным target. class NotFound extends Error {}, а затем err instanceof NotFound даёт true. Старая проблема, когда результат был false, касалась только кода, скомпилированного в ES5, а TypeScript 7 больше не поддерживает target ES5.
Почему "hello" instanceof String равно false?
Строковый литерал это примитив, а не объект, поэтому у него нет цепочки прототипов для проверки. instanceof String истинно только для объектов-обёрток, созданных через new String(). TypeScript отвергает instanceof для значения типа string (TS2358); для примитивов используйте typeof value === "string".