Data Types
The different kinds of values JavaScript can store and work with.
What is it?
Not all values are the same kind of thing. The number 5, the word "hello", and a true/false answer all behave differently. JavaScript groups values into a small set of data types so it knows how to handle each one.
The most common ones you'll use constantly:
- String — text, written in quotes:
"hello" - Number — any number:
42,3.14 - Boolean — true or false:
true,false - Undefined — a variable that has been declared but has no value yet
- Null — a value that's intentionally empty
- Object — a collection of related data (including arrays and functions)
Explain like I'm 10
Think of a toolbox with different compartments — one for screws, one for nails, one for tape. Data types are those compartments; they tell you what kind of thing you're holding so you know what you can do with it.
Examples
Checking a value's type
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"typeof is a built-in operator that tells you the data type of any value.
The same operator, different types, different behavior
console.log(2 + 3); // 5 — both numbers, so + adds them
console.log("2" + "3"); // "23" — both strings, so + joins them
console.log("2" + 3); // "23" — mixed, so the number becomes a string firstThe + operator behaves differently depending on the types of its two values — this is exactly why knowing a value's type matters.
How it works
When JavaScript stores a value, it tags it internally with a type. This tag determines which operations are allowed — you can do math on numbers, but adding two strings joins them together instead ("2" + "3" becomes "23", not 5). Knowing the type of a value tells you how it will behave.
Why does it exist?
Different kinds of data need different rules. Text needs to be joined and searched; numbers need to be added and compared; true/false values need to drive decisions. Types let the language apply the right rules automatically.
When to use it
You actively think about data types whenever you're not sure what kind of value you're dealing with — checking user input, debugging an unexpected result, or deciding whether two values can be safely compared or combined. typeof is the quick way to check.
When not to use it
You don't need to manually check the type of a value you created yourself and already know the shape of — sprinkling typeof checks everywhere just adds noise. Save type-checking for boundaries: user input, API responses, and function arguments coming from code you don't control.
Common mistakes
Mixing up a number and a string that looks like a number, e.g.
"5" + 1gives"51", not6.Confusing
undefined(nothing assigned yet) withnull(intentionally empty).Forgetting that arrays and functions are technically objects too.
Practice exercises
- Easy:
Use
typeofto check the type of a string, a number, and a boolean. - Medium:
Predict the output of
"3" + 3and3 + 3, then check by running it. - Hard:
Write a function
describeType(value)that returns a friendly sentence describing the value's type.
Interview questions
What are the basic data types built into JavaScript?
Seven primitive types — String, Number, Boolean, Undefined, Null, Symbol, and BigInt — plus Object, which covers everything else: plain objects, arrays, functions, dates, and more.
What's the difference between a primitive and an object?
A primitive holds its actual value directly and is compared/copied by value — two strings with the same characters are equal. An object holds a reference to a location in memory, and variables pointing to it are compared/copied by that reference — two separately created objects with identical contents are not === equal.
What does `typeof` return for a string, a number, and a boolean?
"string", "number", and "boolean" respectively — typeof returns a string naming the value's type, which is useful for quick checks at runtime.
What's the difference between `null` and `undefined`?
undefined is what JavaScript itself assigns automatically — a declared-but-unassigned variable, a missing function argument, a missing object property — it means nothing has been set here yet. null is a value a developer assigns deliberately to represent intentionally empty or no value.
What is `NaN`, and what does the name stand for?
"Not a Number" — it's the special value returned by numeric operations that don't produce a valid number, like 0 / 0 or Number("abc"). Despite the name, typeof NaN is "number", since it's still technically a member of the Number type.
Is an array its own separate data type in JavaScript?
No — arrays are a specialized kind of object (with numeric-like indices and a length property), not a distinct primitive type. typeof [] returns "object", and checking for an array specifically requires Array.isArray().
Is a function a data type in JavaScript?
Functions are objects too — technically callable objects. typeof treats them specially and returns "function" rather than "object", which is the one case where typeof distinguishes a callable object from a plain one.
What does `typeof null` return, and why is that surprising?
It returns "object", even though null is one of the primitive types, not an object. It's a long-standing bug from the original 1995 implementation — null was represented internally with the same type tag as objects — and it's been kept ever since purely for backward compatibility.
What does `typeof` return for an array, and how would you actually check for one?
typeof [] returns "object", same as for any plain object — typeof can't tell arrays apart from other objects. Use Array.isArray(value) instead, which checks specifically for array-ness.
What does `typeof` return for a function?
"function" — the one case where typeof gives a more specific answer than "object" for something that's technically an object under the hood.
What is type coercion?
The automatic conversion of a value from one type to another that JavaScript performs when an operation expects a different type than what it was given — e.g. converting a number to a string so + can join it with an existing string.
Why does `"2" + 3` produce `"23"` while `"2" - 1` produces `1`?
+ has a special rule: if either operand is a string, it converts the other operand to a string and concatenates. Every other arithmetic operator, including -, has no string-joining behavior at all, so it instead converts both operands to numbers first — "2" becomes 2, and 2 - 1 is 1.
What's the difference between implicit and explicit type conversion?
Implicit conversion (coercion) happens automatically as a side effect of an operation, like "5" * 2 silently becoming 10. Explicit conversion is when the code deliberately converts a value, like Number("5") or String(5), making the intent visible instead of relying on an operator's built-in rules.
How would you explicitly convert a string to a number?
Number("42"), parseInt("42") / parseFloat("42.5"), or the unary +"42" shorthand all work — Number() and unary + require the whole string to be numeric or they return NaN, while parseInt/parseFloat parse as much of a leading numeric portion as they can and ignore the rest.
How would you explicitly convert a number to a string?
String(42), (42).toString(), or concatenating with an empty string like 42 + "" (which relies on implicit coercion rather than being truly explicit) all produce "42".
What is `BigInt`, and why does it exist?
A primitive type for representing whole numbers larger than Number can safely hold (Number.MAX_SAFE_INTEGER, 2^53 - 1) without losing precision. You create one by appending n to an integer literal, e.g. 123n, and BigInt values can't be mixed with regular numbers in arithmetic without an explicit conversion.
What is `Symbol`, and what is it typically used for?
A primitive type that produces a guaranteed-unique value every time it's created (Symbol("id") !== Symbol("id")), commonly used as an object property key that won't collide with any string key or another symbol — useful for adding metadata to objects without risking a name clash.
Why is `NaN === NaN` false?
By the IEEE 754 floating-point specification (which JavaScript's Number type follows), NaN is defined to never equal anything, including itself — it represents "not a valid numeric result" rather than any specific value that could be compared.
How do you correctly check whether a value is `NaN`?
Number.isNaN(value), which only returns true for the actual NaN value. The older global isNaN(value) first coerces its argument to a number, so isNaN("hello") also returns true even though "hello" isn't literally NaN.
What's the difference between `Number.isNaN()` and the global `isNaN()`?
Number.isNaN() checks strictly — it returns true only if the value is exactly NaN, no conversion involved. The global isNaN() coerces its argument to a number first, which means non-numeric values like isNaN("abc") also return true, even though "abc" was never NaN to begin with.
Is JavaScript strongly or weakly typed, and what does that mean in practice?
Weakly typed — operators freely convert between types instead of raising errors when types don't match, e.g. "5" * 2 silently becomes 10 rather than throwing. This makes some code more forgiving to write but is a common source of subtle bugs when a conversion happens somewhere the developer didn't intend.
Is JavaScript statically or dynamically typed?
Dynamically typed — a variable's type isn't checked or fixed at compile time; the type lives with the current value and is only known and checked while the code actually runs. This is what TypeScript's static type system is layered on top to address.
Can a variable's type change after it's declared?
Yes — since JavaScript is dynamically typed, a variable is just a name bound to whatever value it currently holds. let x = 5; x = "now text"; is completely legal; the variable itself has no fixed type, only the value assigned to it at any given moment does.
Why are primitives compared by value while objects are compared by reference?
Primitives are stored directly, so comparing two of them means comparing their actual contents — "cat" === "cat" is true because the characters match. Objects are stored as a reference to a location in memory, so === compares whether two variables point to the exact same object, not whether their contents look the same — two separately created objects with identical properties are still !==.
What happens when you access a property on a primitive, like `"hello".length`?
JavaScript temporarily wraps the primitive in its corresponding object type (a String object, here), reads the property off that wrapper, and then discards the wrapper immediately — the primitive itself never actually becomes an object; this "auto-boxing" just makes property/method access on primitives work transparently.
Output-prediction: what does `typeof typeof 1` evaluate to?
"string". The inner typeof 1 evaluates first and returns the string "number"; the outer typeof then runs on that string value, and the type of any string is "string".
Output-prediction: what does `console.log(1 + "1"); console.log(1 - "1");` log?
It logs "11" then 0. + sees a string operand and coerces the number to a string, concatenating them. - has no string-joining behavior, so it coerces the string "1" to the number 1 instead, giving 1 - 1 = 0.
Output-prediction: what does `console.log([1, 2, 3] + [4, 5, 6])` log?
It logs the string "1,2,34,5,6". + on two objects (arrays are objects) coerces both to strings first — an array's default string conversion joins its elements with commas — producing "1,2,3" and "4,5,6", which are then concatenated.
Output-prediction: what does `null == undefined` evaluate to? What about `null === undefined`?
null == undefined is true — the specification special-cases loose equality between null and undefined to treat them as equal to each other (but to nothing else). null === undefined is false, because strict equality also requires the same type, and Null and Undefined are different types.
Output-prediction: what does `typeof NaN` return?
"number". Despite meaning "not a number," NaN is a special value that still belongs to the Number type — it represents an invalid numeric result, not an absence of a number.