The typeof operator in JavaScript
typeof returns a string describing the type of its operand. It runs at runtime and produces one of 8 possible results.
Theory
TL;DR
- Think of
typeofas a shipping label scanner: primitives get unique tags ("number", "string"), but every object gets the same generic "object" tag regardless of what's inside. - Main limit:
{},[], andnullall return"object". No distinction between them. - Decision rule: use
typeoffor primitive checks; useArray.isArray(),=== null, orinstanceoffor objects.
Quick example
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" -- same result as {}
typeof null; // "object" -- bug from 1995, never fixed
typeof NaN; // "number" -- NaN is still a number typeThree results trip up developers most often: arrays, null, and NaN.
Key difference
typeof reads an internal tag stored on the value, not the value's structure or constructor. For each primitive type the tag is unique. For all objects (arrays included) and null, the tag is the same: "object". Functions are the one exception: the JS spec gives them a distinct tag, so typeof function(){} returns "function", not "object".
When to use
- Primitive guard:
if (typeof x === "string")before calling string methods - Callback check:
typeof fn === "function"before invoking a passed function - Undeclared variable:
typeof undeclaredVarreturns"undefined"safely, no ReferenceError thrown - Not for objects: use
Array.isArray(arr)for arrays,value === nullfor null,instanceoffor class instances
How the engine handles this
V8 implements typeof as a single bytecode operation. It reads one tag from the value's memory layout: numbers carry a Smi tag, objects point to a HeapObject map. The result comes back in under a nanosecond. null has shared the object tag since Netscape 2.0 and was never corrected, because fixing it would break too much of the existing web.
Common mistakes
Mistake 1: Assuming typeof x === "object" means a plain object.
typeof []; // "object"
typeof null; // "object"
// Fix: combine checks
if (x !== null && typeof x === "object" && !Array.isArray(x)) {
// x is actually a plain object
}Mistake 2: Trying to detect NaN with typeof.
typeof NaN; // "number" -- NaN is a valid IEEE 754 number type
// Fix:
Number.isNaN(NaN); // true
Number.isNaN("hello"); // false -- no coercionMistake 3: Expecting typeof to tell arrays apart from objects.
typeof []; // "object" -- not "array"
// Fix:
Array.isArray([]); // trueMistake 4: Accessing an undeclared variable directly instead of using typeof.
console.log(undeclaredVar); // ReferenceError
console.log(typeof undeclaredVar); // "undefined" -- safe
// Practical use: environment check in SSR / Next.js
if (typeof window !== "undefined") {
// browser-only code
}Real-world usage
- React:
if (typeof onClick !== "function") return null;to guard against a missing prop - Express.js:
if (typeof req.body.userId !== "string") return res.status(400)for input validation - Node.js:
if (typeof callback === "function") fs.readFile(..., callback)in callback-based APIs - Lodash:
_.isString(val)starts withtypeof val === "string"internally
The typeof window !== "undefined" check appears in nearly every SSR project I have worked on. It is the simplest way to branch browser-only code without crashing on the server.
Follow-up questions
Q: What does typeof null return, and why?
A: It returns "object". This is a bug from 1995: the original JavaScript stored values with numeric type tags, and null had tag 0, which also meant "object". Fixing it would break too much existing code, so the spec keeps it unchanged.
Q: How do you properly check if a value is an array?
A: Use Array.isArray(value). It works across iframes, unlike instanceof Array, which fails when the value comes from a different frame's constructor.
Q: What is the difference between typeof and instanceof?
A: typeof returns a string tag and works on primitives. instanceof checks the prototype chain and only works on objects. It also breaks across iframes because each frame has its own Array and Object constructors.
Q: Why does typeof undeclaredVariable not throw a ReferenceError?
A: It is the one place in JavaScript where an undeclared identifier is allowed without an error. The spec makes this exception so you can safely check for optional globals and environment features.
Q: Why is typeof so fast in V8?
A: It reads one tag from the value's internal memory. No prototype chain walk, no heap allocation. A single bytecode instruction.
Examples
Basic: Type guard before processing
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 typetypeof guards each branch before any method call. Passing an array falls through to the error because typeof [] === "object", not "array".
Intermediate: Prop validation in a React component
function UserCard({ user, onClick }) {
if (typeof user !== "object" || user === null) {
return <div>Invalid user data</div>;
}
if (typeof onClick !== "function") {
console.warn("onClick must be a function");
return null;
}
return <div onClick={onClick}>{user.name}</div>;
}
// The null check alongside typeof is required:
// typeof null === "object", so without it a null user passes the first guard.Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.