Пошук уроків, статей та іншого контенту
Розберіться, як instanceof визначає тип екземпляра, а in — наявність властивості в об’єкті.
instanceofОператор instanceof перевіряє, чи створено об’єкт за допомогою певного класу або конструктора. Результат перевірки — логічне значення true або false.
Синтаксис:
об'єкт instanceof КласНаприклад:
class User {
constructor(public name: string) {}
}
const user = new User("Олена");
console.log(user instanceof User); // true
console.log(user instanceof Date); // falseОб’єкт user створено через new User(), тому перевірка user instanceof User повертає true.
instanceof зручно використовувати, коли змінна може містити об’єкти різних класів:
class EmailMessage {
send(): void {
console.log("Надсилання електронного листа");
}
}
class SmsMessage {
send(): void {
console.log("Надсилання SMS");
}
}
function sendMessage(message: EmailMessage | SmsMessage): void {
if (message instanceof EmailMessage) {
console.log("Тип повідомлення: email");
message.send();
} else {
console.log("Тип повідомлення: SMS");
message.send();
}
}
sendMessage(new EmailMessage());
sendMessage(new SmsMessage());Після перевірки TypeScript розуміє, з яким класом працює програма в певній гілці if. Це називається звуженням типу — TypeScript уточнює тип змінної на основі перевірки.
instanceof і вбудовані типиОператор також можна використовувати з вбудованими конструкторами JavaScript:
const date = new Date();
const items = [1, 2, 3];
const error = new Error("Помилка");
console.log(date instanceof Date); // true
console.log(items instanceof Array); // true
console.log(error instanceof Error); // trueДля масивів частіше використовують спеціальний метод Array.isArray:
const value: unknown = [1, 2, 3];
if (Array.isArray(value)) {
console.log(value.length); // TypeScript знає, що value — масив
}instanceofinstanceof працює з об’єктами та ланцюжком прототипів. Він не перевіряє, чи має об’єкт такі самі властивості, як певний інтерфейс.
Інтерфейси TypeScript існують лише під час перевірки коду і видаляються під час виконання JavaScript:
interface Product {
name: string;
}
const product: Product = {
name: "Ноутбук",
};
// Така перевірка неможлива:
// product instanceof ProductІнтерфейс Product не є класом або конструктором, тому використати його з instanceof не можна.
Якщо потрібно перевірити структуру звичайного об’єкта, для цього підходить оператор in.
inОператор in перевіряє, чи існує властивість із певним ім’ям в об’єкті.
Синтаксис:
"ім'яВластивості" in об'єктРезультатом також є true або false:
const user = {
name: "Олена",
age: 28,
};
console.log("name" in user); // true
console.log("email" in user); // falseВажливо: in перевіряє саме наявність властивості, а не її значення.
const settings = {
theme: undefined,
};
console.log("theme" in settings); // true
console.log(settings.theme); // undefinedВластивість theme існує, хоча її значення дорівнює undefined.
in для звуження типуНайчастіше в TypeScript in використовують, коли значення може мати одну з кількох форм:
type EmailContact = {
email: string;
};
type PhoneContact = {
phone: string;
};
function printContact(contact: EmailContact | PhoneContact): void {
if ("email" in contact) {
console.log(`Email: ${contact.email}`);
} else {
console.log(`Телефон: ${contact.phone}`);
}
}
printContact({ email: "olena@example.com" });
printContact({ phone: "+380501234567" });У першій гілці TypeScript знає, що contact має властивість email. В іншій гілці залишається тип PhoneContact, тому доступна властивість phone.
type ClickEvent = {
type: "click";
x: number;
y: number;
};
type KeyEvent = {
type: "key";
key: string;
};
function describeEvent(event: ClickEvent | KeyEvent): string {
if ("x" in event && "y" in event) {
return `Клік у точці (${event.x}, ${event.y})`;
}
return `Натиснуто клавішу: ${event.key}`;
}
console.log(describeEvent({ type: "click", x: 100, y: 50 }));
console.log(describeEvent({ type: "key", key: "Enter" }));Оператор in дає змогу визначити форму об’єкта за властивістю, яка характерна лише для одного з типів.
instanceof та inОбидва оператори використовують для перевірок, але перевіряють різні речі:
instanceof перевіряє, чи є об’єкт екземпляром певного класу або конструктора.
in перевіряє, чи існує властивість із певним ім’ям в об’єкті.
instanceof підходить для класів.
in підходить для об’єктів, описаних інтерфейсами або типами.
instanceof перевіряє ланцюжок прототипів.
in також може знаходити властивості, успадковані через прототип.
class Admin {
permissions: string[] = ["read", "write"];
}
type Guest = {
visit(): void;
};
const admin = new Admin();
const guest: Guest = {
visit() {
console.log("Гість переглядає сторінку");
},
};
console.log(admin instanceof Admin); // true
console.log("permissions" in admin); // true
console.log("visit" in guest); // truein повертає true, якщо властивість є:
безпосередньо в об’єкті;
успадкованою від його прототипу.
const user = {
name: "Олена",
};
console.log("name" in user); // true
console.log("toString" in user); // trueМетод toString не записаний безпосередньо в об’єкті user, але він доступний через прототип.
Для перевірки лише власної властивості можна використати Object.hasOwn:
const user = {
name: "Олена",
};
console.log(Object.hasOwn(user, "name")); // true
console.log(Object.hasOwn(user, "toString")); // falseУ задачах зі звуженням типів зазвичай використовують саме in, тому що потрібно перевірити доступність властивості в об’єкті.
instanceof та inУ програмі можна використовувати обидві перевірки залежно від типів даних:
class FileReport {
constructor(public fileName: string) {}
}
type TextReport = {
text: string;
};
function printReport(report: FileReport | TextReport): void {
if (report instanceof FileReport) {
console.log(`Звіт у файлі: ${report.fileName}`);
} else if ("text" in report) {
console.log(`Текстовий звіт: ${report.text}`);
}
}
printReport(new FileReport("report.pdf"));
printReport({ text: "Звіт за поточний місяць" });Тут:
instanceof FileReport перевіряє екземпляр класу.
"text" in report перевіряє наявність властивості в об’єкті іншого типу.
Нижче функція обробляє результат операції. Успішний результат має властивість data, а результат із помилкою — error.
type SuccessResult = {
data: string;
};
type ErrorResult = {
error: string;
};
function handleResult(result: SuccessResult | ErrorResult): void {
if ("data" in result) {
console.log(`Успіх: ${result.data}`);
} else {
console.log(`Помилка: ${result.error}`);
}
}
handleResult({ data: "Дані завантажено" });
handleResult({ error: "Не вдалося виконати запит" });Цей підхід корисний для об’єктів, які можуть мати різні набори властивостей.
instanceofinterface User {
name: string;
}
// Неправильно: інтерфейс не існує під час виконання
// value instanceof UserДля інтерфейсів використовуйте in або перевірку окремих властивостей.
const data = {
value: 0,
};
console.log("value" in data); // true
console.log(Boolean(data.value)); // falseВластивість value існує, але її значення 0 перетворюється на false у логічному контексті. Це різні перевірки.
in не з об’єктомЛіворуч від in має бути ім’я властивості, а праворуч — об’єкт. Не передавайте туди null або undefined:
const value: unknown = null;
// Небезпечно: спричинить помилку під час виконання
// "name" in valueЯкщо значення має тип unknown, спочатку переконайтеся, що це об’єкт:
function hasName(value: unknown): boolean {
return (
typeof value === "object" &&
value !== null &&
"name" in value
);
}
console.log(hasName({ name: "Олена" })); // true
console.log(hasName(null)); // falseОб’єкт із потрібною властивістю не стає екземпляром класу автоматично:
class User {
constructor(public name: string) {}
}
const userLike = {
name: "Олена",
};
console.log(userLike instanceof User); // false
console.log("name" in userLike); // trueuserLike має поле name, але його не створено через new User().
instanceof перевіряє, чи є об’єкт екземпляром певного класу.
in перевіряє наявність властивості в об’єкті.
instanceof не можна застосовувати до інтерфейсів і типів TypeScript.
in часто використовують для звуження об’єднаних типів.
Перевірка "property" in object не залежить від значення властивості.
Перед використанням in переконайтеся, що праворуч знаходиться об’єкт.
Для перевірки лише власної властивості використовуйте Object.hasOwn.