The Eight Types
Mental model: Seven primitives and one object type, and typeof is your first question about any value.
Level: beginner · about 11 minutes
console.log(typeof 'text'); // 'string'
console.log(typeof 42); // 'number'
console.log(typeof 9007199254740993n); // 'bigint'
console.log(typeof true); // 'boolean'
console.log(typeof undefined); // 'undefined'
console.log(typeof Symbol('id')); // 'symbol'
console.log(typeof null); // 'object' <-- wrong
console.log(typeof { a: 1 }); // 'object'Run this before you read anything. One of the eight answers is wrong, and has been since 1995.
Every value in JavaScript is one of eight types: seven primitives (string, number, bigint, boolean, undefined, symbol, null) and object. Arrays, functions, dates, Maps and class instances are not extra types. They are objects with different equipment.
| Type | Example value | typeof says | Worth knowing |
|---|---|---|---|
string | 'hi' | 'string' | immutable, UTF-16 under the hood |
number | 42, 3.14, NaN | 'number' | one type for integers and decimals |
bigint | 9007199254740993n | 'bigint' | exact integers of any size |
boolean | true | 'boolean' | only two values ever |
undefined | undefined | 'undefined' | the absence you did not choose |
symbol | Symbol('id') | 'symbol' | a guaranteed unique key |
null | null | 'object' | the absence you did choose, and a broken typeof |
object | {}, [], () => {} | 'object' or 'function' | everything with properties |
The typeof null bug
const value = null;
console.log(typeof value === 'object'); // true, and useless to you
console.log(value === null); // true, the honest check
console.log(value == undefined); // true, both count as "no value"
Arrays are objects, so ask Array.isArray
console.log(typeof [1, 2, 3]); // 'object', not helpful
console.log(Array.isArray([1, 2, 3])); // true
console.log(Array.isArray('abc')); // false, even though it has a length
console.log(Array.isArray({ 0: 'a' })); // false, array-like is not an array
`typeof x === "object"`- true for
null, arrays, dates,Maps and plain objects alike `Array.isArray(x)`- the only check for arrays you should write
`x === null`- the only check for null you should write
`Number.isNaN(x)`- the only check for NaN you should write
Wrapper objects and autoboxing
A primitive has no properties, so "ada".toUpperCase() looks impossible. When you use a method on a primitive, the engine wraps it in a temporary object, reads the method from that object, runs it, and throws the wrapper away. That is autoboxing, and it happens on every method call.
const name = 'ada';
console.log(name.toUpperCase()); // 'ADA' via a temporary String wrapper
console.log(typeof name); // 'string', still a primitive
const boxed = new String('ada');
console.log(typeof boxed); // 'object'
console.log(boxed == 'ada', boxed === 'ada'); // true false
One more oddity: typeof has nine possible answers, not eight, because functions get their own. That is a convenience, not a ninth type. A function is an object you can call.
console.log(typeof NaN);NaN stands for "not a number", and its type is number. It is the numeric value that represents a failed numeric operation, so it has to live in the number type. Ask Number.isNaN(x) when you want to detect it, because NaN === NaN is false.
Try it yourself
Type probe
const values = ['text', 42, 10n, true, undefined, null, Symbol('id'), { a: 1 }, [1, 2], () => {}];
for (const value of values) {
console.log(String(value).padEnd(14), typeof value);
}
console.log('arrays found:', values.filter(Array.isArray).length);
console.log('nulls found:', values.filter((v) => v === null).length);
Add your own values: a Date, a Map, NaN, a class instance. How many of them report "object"?
Exercises
Write an honest describeType
Write describeType(value) which returns the type as a lowercase string, but fixes what typeof gets wrong: return "null" for null and "array" for arrays. Everything else keeps its typeof answer.
Check yourself
- What does this log?
- 2 — Two values pass:
null(because of the 1995 bug) and[](because arrays are objects). Numbers, strings andundefinedall report their own type. This is exactly why atypeof v === "object"guard is rarely what you want. - Which check reliably tells you a value is an array?
Array.isArray(value)—typeofnever returns"array". Alengthproperty is present on strings and on any array-like object, andinstanceof Objectis true for every object.Array.isArrayis the purpose-built answer and it works across realms, such as an array from an iframe.- Why can you call
.toUpperCase()on a primitive string, which has no properties? - The engine wraps the primitive in a temporary object, runs the method, then discards the wrapper — That temporary wrapping is autoboxing. The wrapper is thrown away immediately, which is why
const s = "a"; s.custom = 1; console.log(s.custom)givesundefined: you set a property on an object that no longer exists.
Common mistakes
- Using
typeof value === "object"as an object check. It is also true fornulland for every array. - Writing
new Number(5)ornew String("a"). You get an object that fails===against the primitive. - Expecting a ninth type for arrays or functions. Both are objects;
typeofjust makes an exception for functions.
Takeaways
- Seven primitives plus
object. Arrays, functions and dates are all objects. typeof null === "object"is a 1995 bug that will never be fixed. Compare with=== null.Array.isArrayis the only array check worth writing.- Methods on primitives work through a temporary wrapper object that is thrown away at once.