typeof null // "object"
typeof undefined // "undefined"
null is not an object. It is a primitive, sitting alongside undefined,
numbers, strings, booleans, symbols and bigints. So why does typeof disagree?
The actual cause
In the original 1995 JavaScript implementation, values were stored as a pair: a small type tag, and the data itself. The tag occupied the low bits of a 32-bit word:
| Tag | Type |
|---|---|
000 |
object — the data is a reference |
001 |
integer |
010 |
double |
100 |
string |
110 |
boolean |
null was represented as the null pointer — all bits zero. Its type tag was
therefore 000, which is indistinguishable from the tag for "object".
typeof read the tag and answered accordingly. It was not a special case or an
oversight in the operator; null genuinely looked like an object to the code
doing the checking.
Why it was never fixed
It was proposed. In 2013, during ES6 discussions, a change was floated to make
typeof null === "null". It was rejected.
The reason is that a very large amount of code in the wild is written like this:
if (typeof value === 'object') {
// assume it might be null and check
if (value !== null) { ... }
}
Changing the return value would silently alter which branch that code takes on millions of pages, most of which nobody maintains any more. JavaScript's commitment to not breaking the web means a wart this small stays permanently.
What to use instead
For a null check, compare directly:
value === null
To catch both null and undefined, use loose equality with null. This is the
one case where == is genuinely the right tool, because it matches exactly those
two values and nothing else:
value == null // true for null and undefined, false for 0, '', NaN
To tell a real object from null:
function isObject(value) {
return typeof value === 'object' && value !== null
}
And if you want an accurate type for anything at all:
function typeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase()
}
typeOf(null) // "null"
typeOf([]) // "array"
typeOf(new Date()) // "date"
typeOf(/x/) // "regexp"
That form reads an internal tag that, unlike typeof, does distinguish these
cases.
The related gotcha
typeof has a second surprise that shows up in the same interview:
typeof [] // "object"
typeof function(){} // "function"
Arrays report as objects, which is technically correct — an array is an object
— but rarely what you want. Use Array.isArray().
Functions report as "function" even though they are objects too, because
typeof special-cases anything callable.
Why interviewers ask
On its own, this is trivia. What it actually probes is whether you know that
null and undefined are distinct, and whether you reach for === null rather
than trusting typeof. A candidate who explains the tagged-union cause has
usually read about the language rather than only used it — which is the real
signal.