typeof is an operator that tells you what type a value is, as a string. It is the quickest type check in JavaScript and works well for primitives, but it has a few famous blind spots. This lesson covers every result and when to use something else.
typeof only ever returns one of eight strings:
| Expression | Result |
|---|---|
| typeof "text" | "string" |
| typeof 42 / typeof NaN | "number" |
| typeof 42n | "bigint" |
| typeof true | "boolean" |
| typeof undefined | "undefined" |
| typeof Symbol() | "symbol" |
| typeof function(){} / typeof class {} | "function" |
| typeof {} / typeof [] / typeof new Date() | "object" |
| typeof null | "object" (a bug from 1995) |
typeof 42 // "number"
typeof typeof 42 // "string" (the result of typeof is a string)
if (typeof x === "number") { } // compare against a string, in quotes
typeof x === number (no quotes) compares against a variable named number, which does not exist. Always quote the type name.
typeof is an operator like !, not a function. Parentheses are allowed but only group the expression:
typeof "a" + 1 // "string1" typeof runs first, then + joins
typeof ("a" + 1) // "string" parentheses group the expression first
const v = null;
typeof v === "object" // true: misleading
v === null // true: the right check
This means "is it an object?" needs two checks:
const isObject = v => v !== null && typeof v === "object";
Every kind of object except functions reports "object". Use a more specific check:
typeof [1, 2] // "object"
Array.isArray([1, 2]) // true
new Date() instanceof Date // true
const result = "abc" * 2;
typeof result // "number" (but it is NaN)
Number.isFinite(result) // false the check you actually want
Using a variable that was never declared normally throws an error. typeof is the one safe exception:
console.log(mystery); // ReferenceError: mystery is not defined
console.log(typeof mystery); // "undefined" no error
That makes it useful for checking whether a feature exists before using it:
if (typeof structuredClone === "function") {
// safe to use structuredClone in this browser
}
let or const used in its temporal dead zone (before its line) still throws, even inside typeof. The safety only applies to names that are not declared anywhere in scope.
typeof cannot tell objects apart. instanceof can: it asks "was this object made by that constructor?"
const time = new Date();
const fruits = ["apples", "bananas", "oranges"];
const prices = new Map([["apples", 500], ["bananas", 300]]);
const unique = new Set(["apples", "bananas"]);
console.log(time instanceof Date, fruits instanceof Array);
console.log(prices instanceof Map, unique instanceof Set);
console.log(fruits instanceof Object); // every array is also an Object
console.log("hi" instanceof String); // primitives are not instances of anything
Every value except null and undefined has a constructor property: the function that made it (for primitives, the wrapper that auto-boxing uses):
console.log([1, 2, 3].constructor === Array);
console.log(new Date().constructor === Date);
console.log(({ name: "John" }).constructor.name);
console.log((function () {}).constructor.name, "hi".constructor.name);
constructor is an ordinary property, so any object can have its own. After const fake = { constructor: Array };, fake.constructor === Array is true, but Array.isArray(fake) is false. Prefer Array.isArray and instanceof.
{name:'John',age:34}.constructor and function () {}.constructor. At the start of a statement, { opens a code block and function starts a function declaration, so these are SyntaxError: Unexpected token ':' and SyntaxError: Function statements require a function name. Wrap them in parentheses, as above.const fruits three times in a row. In one program, the second is SyntaxError: Identifier 'fruits' has already been declared."hi".length works anyway.void runs an expression, throws away the result, and always gives undefined:
let n = 0;
console.log(void 0);
console.log(void (n = 5), n); // the assignment still happens
console.log(void 0 === undefined);
<a href="javascript:void(0);">: a link that goes nowhere, so that JavaScript can handle the click instead. Avoid it. It mixes code into HTML, a link that goes nowhere confuses screen readers and keyboard users, and it breaks "open in new tab." If clicking something runs code, make it a <button>. In modern code you rarely need void at all: just write undefined.
function typeName(v) {
if (v === null) return "null";
if (Array.isArray(v)) return "array";
if (typeof v === "number" && Number.isNaN(v)) return "NaN";
return typeof v;
}
[null, [], NaN, 5, "hi", {}].map(typeName);
What does this log?
console.log(typeof typeof undefined);
string. typeof undefined is the string "undefined", and typeof of any string is "string".What is the most reliable way to check whether x is an array?
typeof x === "array"x.constructor === ArrayArray.isArray(x)typeof x === "object"typeof has no "array" result. B can be faked by any object with its own constructor property. D is also true for plain objects, dates, and null.What does void (total = 10) give, and does total change?
undefined, and yes, total becomes 10. void runs the expression and only throws away its result.typeof line for every row of the table above and check the resultstypeof typeof nulltypeof to safely check for a variable you never declaredtypeName example with its Try it Yourself button and extend it so it also reports "date" for Date objects