Skip to main content

Оператор typeof у JavaScript

typeof повертає рядок з типом операнда. Оператор виконується під час роботи програми і може дати одне з 8 можливих значень.

Теорія

TL;DR

  • typeof схожий на сканер ярликів на складі: примітиви отримують унікальні теги ("number", "string"), але всі об'єкти отримують однаковий тег "object", незалежно від вмісту.
  • Головне обмеження: {}, [] і null повертають "object". Різниці між ними немає.
  • Правило вибору: typeof для примітивів; Array.isArray(), === null або instanceof для об'єктів.

Швидкий приклад

javascript
typeof 42; // "number" typeof "hello"; // "string" typeof true; // "boolean" typeof undefined; // "undefined" typeof Symbol("id"); // "symbol" typeof 42n; // "bigint" typeof function(){}; // "function" typeof {}; // "object" typeof []; // "object" -- те саме, що й {} typeof null; // "object" -- баг з 1995 року, так і не виправлений typeof NaN; // "number" -- NaN залишається числовим типом

Три результати дивують розробників найчастіше: масиви, null і NaN.

Ключова різниця

typeof зчитує внутрішній тег значення, а не його структуру чи конструктор. Для кожного примітивного типу тег унікальний. Для всіх об'єктів (включно з масивами) і null тег однаковий: "object". Виняток складають функції: специфікація JS дає їм окремий тег, тому typeof function(){} повертає "function", а не "object".

Коли використовувати

  • Захист типу: if (typeof x === "string") перед викликом рядкових методів
  • Перевірка колбека: typeof fn === "function" перед викликом переданої функції
  • Неоголошена змінна: typeof undeclaredVar повертає "undefined" без ReferenceError
  • Не для об'єктів: використовуй Array.isArray(arr) для масивів, value === null для null, instanceof для екземплярів класів

Як це працює всередині

V8 реалізує typeof як одну байткод-операцію. Він зчитує тег з внутрішнього представлення значення в пам'яті: числа мають тег Smi, об'єкти вказують на HeapObject map. Перевірка займає менше наносекунди. null ділить тег об'єкта ще з часів Netscape 2.0 і ніколи не виправлявся, щоб не зламати існуючі сайти.

Поширені помилки

Помилка 1: Думати, що typeof x === "object" означає звичайний об'єкт.

javascript
typeof []; // "object" typeof null; // "object" // Виправлення: поєднай перевірки if (x !== null && typeof x === "object" && !Array.isArray(x)) { // тільки тепер x — справді звичайний об'єкт }

Помилка 2: Перевіряти NaN через typeof.

javascript
typeof NaN; // "number" -- NaN є числом за стандартом IEEE 754 // Виправлення: Number.isNaN(NaN); // true Number.isNaN("hello"); // false -- без приведення типів

Помилка 3: Очікувати, що typeof розрізнить масив і об'єкт.

javascript
typeof []; // "object" -- не "array" // Виправлення: Array.isArray([]); // true

Помилка 4: Звертатися до неоголошеної змінної напряму.

javascript
console.log(undeclaredVar); // ReferenceError console.log(typeof undeclaredVar); // "undefined" -- безпечно // Практичне застосування: перевірка середовища у SSR / Next.js if (typeof window !== "undefined") { // код тільки для браузера }

Де зустрічається в реальному коді

  • React: if (typeof onClick !== "function") return null; для захисту від відсутнього пропа
  • Express.js: if (typeof req.body.userId !== "string") return res.status(400) для валідації запитів
  • Node.js: if (typeof callback === "function") fs.readFile(..., callback) у callback-based API
  • Lodash: _.isString(val) всередині починається з typeof val === "string"

Перевірка typeof window !== "undefined" є майже в кожному SSR-проєкті, з яким я працював. Це найпростіший спосіб відокремити браузерний код від серверного без помилок.

Питання на співбесіді

Q: Що повертає typeof null і чому?
A: Повертає "object". Це баг з 1995 року: перша реалізація JavaScript зберігала значення з числовими тегами, і null мав тег 0, який означав "object". Виправити це неможливо без ризику зламати величезну кількість існуючого коду.

Q: Як правильно перевірити, чи є значення масивом?
A: Використовуй Array.isArray(value). Він працює навіть між iframe-ами, на відміну від instanceof Array, який ламається, коли значення прийшло з іншого фрейму.

Q: У чому різниця між typeof і instanceof?
A: typeof повертає рядковий тег і працює з примітивами. instanceof перевіряє ланцюжок прототипів і працює лише з об'єктами. До того ж, instanceof ламається між iframe-ами, бо кожен фрейм має власний конструктор Array і Object.

Q: Чому typeof undeclaredVariable не кидає ReferenceError?
A: Це єдиний виняток в JavaScript, де неоголошений ідентифікатор не викликає помилки. Специфікація зробила такий виняток, щоб можна було безпечно перевіряти наявність опціональних глобалів.

Q: Чому typeof такий швидкий у V8?
A: Він зчитує один тег з внутрішнього представлення значення в пам'яті. Немає обходу прототипів, немає алокацій. Одна байткод-інструкція.

Приклади

Базовий: захист типу перед обробкою

javascript
function processInput(input) { if (typeof input === "number") { return input * 2; } if (typeof input === "string") { return input.toUpperCase(); } throw new Error("Unsupported type"); } processInput(5); // 10 processInput("hi"); // "HI" processInput([]); // Error: Unsupported type

typeof охороняє кожну гілку перед викликом методу. Масив потрапляє в помилку, бо typeof [] === "object", а не "array".

Середній: перевірка пропсів у React-компоненті

javascript
function UserCard({ user, onClick }) { if (typeof user !== "object" || user === null) { return <div>Некоректні дані користувача</div>; } if (typeof onClick !== "function") { console.warn("onClick має бути функцією"); return null; } return <div onClick={onClick}>{user.name}</div>; } // Перевірка user === null обов'язкова: // typeof null === "object", тому без неї null пройде першу умову.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?