Універсального способу немає - для різних типів різні інструменти.
typeof - для примітивів і функцій:
typeof 'x'; // 'string'
typeof 1; // 'number' (і для NaN теж)
typeof 1n; // 'bigint'
typeof undefined; // 'undefined'
typeof Symbol(); // 'symbol'
typeof (() => {}); // 'function'
typeof null; // 'object' - історична помилка
typeof []; // 'object'
Масив: Array.isArray(value), а не typeof чи instanceof.
instanceof - чи є в ланцюжку прототипів конструктор: err instanceof TypeError. Пастка - різні realm'и: масив з iframe чи з іншого vm-контексту в Node.js має інший Array, і instanceof Array дає false. Array.isArray таку проблему не має.
Точний «внутрішній» тип:
Object.prototype.toString.call(new Date()); // '[object Date]'
Object.prototype.toString.call(null); // '[object Null]'
Інші корисні перевірки:
Number.isNaN(x),Number.isInteger(x),Number.isFinite(x)- на відміну від глобальнихisNaN/isFinite, не приводять аргумент до числа.value === null- дляnull.value !== null && typeof value === 'object'- «справжній» об'єкт.
Для даних ззовні (відповідь API, localStorage, форма) ручні перевірки швидко стають громіздкими. Тут використовують схеми валідації (Zod, Valibot): вони одночасно перевіряють дані під час виконання й дають TypeScript-тип.