What are the data types in JavaScript?
JavaScript has 8 data types — 7 primitives (String, Number, BigInt, Boolean, Undefined, Null, Symbol) and 1 reference type (Object with subtypes like Array, Function, Date, RegExp). Primitives are stored by value; objects are stored by reference.
This one comes up as a warm-up in almost every technical round. Interviewers aren't trying to trick you — they want to hear that you know the basics cold before moving on to harder topics
Primitive Data Types in JavaScript
Primitive values are the building blocks of JavaScript. They're immutable, once created, the value itself can't change (though a variable pointing to it can be reassigned). Primitives are stored directly in memory (the stack), making them fast to access.
String
A string is a sequence of characters wrapped in single quotes, double quotes, or backticks.
const name = "Alice";
const greeting = 'Hello, world';
const message = `Welcome, ${name}!`; // template literal
Strings are immutable. If you try to change a character directly, it silently fails:
let str = "hello";
str[0] = "H"; // does nothing
console.log(str); // "hello"
Use template literals (backticks) when you need to embed variables or write multi-line strings. They're cleaner than string concatenation.
Number
JavaScript has only one numeric type: number. It handles both integers and decimals using the IEEE 754 double-precision floating-point standard.
const age = 30;
const pi = 3.14159;
const negative = -7;
Three special number values deserve attention:
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log("hello" * 2); // NaN (Not a Number)
NaN is one of JavaScript's great quirks. It's a number type that represents an invalid numeric result. And it has a uniquely strange property: NaN is the only value in JavaScript not equal to itself.
console.log(NaN === NaN); // false
console.log(NaN == NaN); // false
To safely check for NaN, use Number. isNaN(), not the global isNaN(), which coerces its argument first.
Number. isNaN(NaN); // true
Number. isNaN("hello"); // false (reliable)
isNaN("hello"); // true (unreliable, coerces first)
Safe integer range: JavaScript numbers can safely represent integers between -(2^53 - 1) and 2^53 - 1. Beyond that, you need BigInt.
BigInt
BigInt was introduced in ES2020 to handle integers larger than Number. MAX_SAFE_INTEGER (9,007,199,254,740,991). Append n to any integer literal to create a BigInt.
const big = 9007199254740992n;
const result = big + 1n; // 9007199254740993n
BigInt can't be mixed directly with regular numbers in arithmetic:
42n + 1; // TypeError
42n + 1n; // 43n, correct
When to use BigInt: Cryptography, database IDs, timestamps in microseconds, or any use case where you need precise integers beyond the safe range.
Boolean
A boolean holds one of two values: true or false. Booleans are what comparisons and conditions produce.
const isActive = true;
const hasError = false;
console.log(5 > 3); // true
console.log(5 === "5"); // false
Every value in JavaScript is either "truthy" or "falsy" when evaluated in a boolean context. The falsy values are: false, 0, "", null, undefined, NaN, and 0n. Everything else is truthy.
Undefined
undefined means a variable has been declared but not assigned a value. JavaScript itself sets variables to undefined by default.
let score;
console.log(score); // undefined
function greet(name) {
console.log(name); // undefined if called as greet()
}
undefined also appears when you access an object property that doesn't exist, or when a function returns without a return statement.
Null
null represents the intentional absence of a value. Unlike undefined, which happens automatically, null is set explicitly by the developer.
let user = null; // user is deliberately empty
This distinction matters: undefined says "I wasn't given a value," while null says "I intentionally have no value."
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object", this is a bug (more on this below)
Rule of thumb: Use null when you want to explicitly represent an empty state. Let JavaScript handle undefined on its own, don't set variables to undefined manually.
Symbol
Introduced in ES2015 (ES6), Symbol creates a guaranteed-unique value. No two Symbols are ever equal, even if they have the same description.
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // false
Symbols are most useful as unique property keys on objects, preventing accidental property name collisions in libraries or shared codebases.
const USER_ID = Symbol("userId");
const user = {
[USER_ID]: 12345,
name: "Alice"
};
Symbols don't appear in for... in loops or Object. keys(), making them ideal for internal/private properties.
Reference Types: Objects and Beyond
Everything that isn't a primitive is an object. Objects are stored by reference, the variable holds a pointer to a location in memory (the heap), not the value itself. This has important consequences for equality checks and function arguments.
Plain Objects
Objects store key-value pairs. Keys are strings (or Symbols); values can be any type.
const user = {
name: "Alice",
age: 30,
isAdmin: false
};
console.log(user. name); // "Alice"
console.log(user["age"]); // 30
Arrays
Arrays are objects with numeric indices and a length property. They look different but are fundamentally objects.
const scores = [98, 87, 95];
console.log(scores[0]); // 98
console.log(typeof scores); // "object" (not "array")
console.log(Array. isArray(scores)); // true
This is why you can't use typeof to detect arrays, it returns "object" for all non-primitive types. Use Array. isArray() instead.
Functions
Functions are also objects in JavaScript, they're "callable objects." This means functions can have properties, be stored in variables, and passed as arguments.
function add(a, b) { return a + b; }
console.log(typeof add); // "function" (special case of typeof)
const multiply = (a, b) => a * b;
typeof returns "function" for functions, which is helpful even though they're technically objects under the hood.
Built-in Object Types
JavaScript includes many built-in reference types:
| Type | Example | Use Case |
|---|---|---|
Date |
new Date() |
Date and time operations |
Map |
new Map() |
Key-value pairs with any key type |
Set |
new Set() |
Unique value collections |
RegExp |
/[a-z]+/ |
Pattern matching |
Promise |
new Promise(...) |
Async operations |
Error |
new Error("msg") |
Error handling |
How to Check Data Types in JavaScript
The typeof Operator
typeof returns a string describing a value's type.
typeof "hello" // "string"
typeof 42 // "number"
typeof 42n // "bigint"
typeof true // "boolean"
typeof undefined // "undefined"
typeof Symbol() // "symbol"
typeof {} // "object"
typeof [] // "object"
typeof function(){} // "function"
typeof null // "object" <-- this is the famous bug
The typeof null Bug
typeof null returns "object", and it's been that way since JavaScript was created in 1995. In the original implementation, values were stored with a type tag in their bit representation, and null (the null pointer) used 000 as its bit pattern, which was the same tag as objects.
The bug was discovered early and a fix was proposed, but fixing it would have broken too much existing code. So it remains in the language to this day.
The practical fix is to check for null explicitly:
function isObject(value) {
return typeof value === "object" && value!== null;
}
Array. isArray() and instanceof
For arrays, always use Array. isArray():
Array. isArray([]); // true
Array. isArray({}); // false
Array. isArray("hello"); // false
For other objects, instanceof checks the prototype chain:
new Date() instanceof Date; // true
[] instanceof Array; // true
[] instanceof Object; // true (arrays are objects)
Type Coercion in JavaScript
Type coercion is JavaScript's automatic conversion of a value from one type to another. It happens when you use operators or comparisons between different types. This is one of the most misunderstood aspects of JavaScript data types, and the source of many bugs.
Consider this pair of real-world examples that trip developers up:
console.log(1 + "2"); // "12" (number coerced to string)
console.log(1 - "2"); // -1 (string coerced to number)
The + operator triggers string concatenation when either operand is a string. The - operator has no string meaning, so it triggers numeric conversion instead.
Implicit vs Explicit Coercion
Implicit coercion happens automatically:
"5" * 2 // 10 (string "5" coerced to number)
true + 1 // 2 (true coerced to 1)
false + 1 // 1 (false coerced to 0)
null + 1 // 1 (null coerced to 0)
Explicit coercion is intentional conversion using built-in functions:
Number("42") // 42
String(42) // "42"
Boolean(0) // false
parseInt("42px") // 42
parseFloat("3.14rem") // 3.14
== vs === (Loose vs Strict Equality)
This is the most practically important coercion concept. The == operator allows type coercion before comparing; === does not.
0 == "0" // true (string coerced to number)
0 === "0" // false (different types, no coercion)
null == undefined // true (special case)
null === undefined // false (different types)
false == 0 // true (false coerced to 0)
false === 0 // false
Default rule: Always use === unless you have a specific reason to allow type coercion. The == operator's rules are complex enough that even experienced developers get surprised.
Type Coercion Cheat Sheet
| Expression | Result | Why |
|---|---|---|
1 + "2" |
"12" |
Number coerced to string |
1 - "2" |
-1 |
String coerced to number |
true + 1 |
2 |
true coerced to 1 |
false + 1 |
1 |
false coerced to 0 |
null + 1 |
1 |
null coerced to 0 |
undefined + 1 |
NaN |
undefined coerces to NaN |
"3" * "4" |
12 |
Both strings coerced to numbers |
[] + [] |
"" |
Arrays coerced to empty strings |
[] + {} |
"[object Object]" |
Array to "", object to "[object Object]" |
{} + [] |
0 |
Block + array, array coerced to 0 |
null >= 0 |
true |
null coerced to 0 for >= |
null == 0 |
false |
null only equals null/undefined with == |
The last two rows deserve a special mention. null >= 0 is true but null == 0 is false. This isn't a mistake, it's because >= uses numeric coercion while == has special rules for null. It's counterintuitive, and it's exactly the kind of edge case that shows up in technical interviews.
Primitive vs Reference Types: Key Differences
The distinction between primitive and reference types affects how values are copied and compared.
Stored by Value vs by Reference
Primitives are copied by value. Each variable gets its own independent copy:
let a = 5;
let b = a;
b = 10;
console.log(a); // 5, unchanged
Objects are copied by reference. Both variables point to the same object in memory:
const obj1 = { name: "Alice" };
const obj2 = obj1;
obj2. name = "Bob";
console.log(obj1. name); // "Bob", both changed
This catches many developers off guard. When you pass an object to a function, the function receives a reference to the same object. Mutations inside the function affect the original.
function rename(user) {
user. name = "Bob"; // mutates the original object
}
const alice = { name: "Alice" };
rename(alice);
console.log(alice. name); // "Bob"
Memory: Stack vs Heap
Primitives are stored on the stack, fast, fixed-size memory allocated when a function is called. Objects are stored on the heap, slower, dynamically sized memory that persists until garbage collected.
This is why creating millions of small objects is slower than working with primitives. For performance-critical code, prefer primitives where possible.
Equality Comparison
Two primitives are equal if their values are equal. Two objects are equal only if they reference the same object:
"hello" === "hello" // true (same value)
const a = { x: 1 };
const b = { x: 1 };
a === b // false (different objects, even with same content)
a === a // true (same reference)
To compare objects by content, you need a deep equality function (like Lodash's _. isEqual) or JSON serialization for simple cases.
5 Common JavaScript Type Mistakes
Understanding JavaScript data types is the first step. Avoiding the most common pitfalls is where it gets practical. Here are the mistakes that show up in code reviews most often.
1. Using == Instead of ===
This opens the door to coercion surprises. Adopt === as your default. Most linters (ESLint) flag == usage for this reason.
// Risky
if (userInput == 0) {... } // matches 0, "0", false, ""
// Safe
if (userInput === 0) {... } // matches only the number 0
2. Confusing null and undefined
These are different types representing different situations. null is intentional emptiness you set. undefined is the absence of assignment.
// Bad: manually setting undefined
let result = undefined; // use null instead
// Good: use null for intentional empty state
let result = null;
Checking for "no value" should handle both:
if (value == null) {... } // catches both null and undefined
// equivalent to: value === null || value === undefined
3. Using typeof to Detect NaN
typeof NaN returns "number", which is technically correct (NaN is a number type) but practically misleading. Use Number. isNaN().
typeof NaN === "number" // true, surprising but correct
Number. isNaN(NaN) // true, what you actually want
Number. isNaN("hello") // false, reliable
isNaN("hello") // true, unreliable (coerces first)
4. Using typeof to Check Arrays
As covered earlier, typeof [] returns "object". Always use Array. isArray():
// Wrong
if (typeof data === "array") {... } // this NEVER runs
// Right
if (Array. isArray(data)) {... }
5. Not Guarding Against null Before Property Access
Accessing a property on null or undefined throws a TypeError. This is one of the most common runtime errors in JavaScript.
// This crashes if user is null
const name = user. name; // TypeError: Cannot read properties of null
// Guard with optional chaining
const name = user?. name; // undefined if user is null
// Or with an explicit check
const name = user!== null? user. name: "Guest";
Optional chaining (?.) was introduced in ES2020 and is now the standard way to safely access potentially null/undefined properties.
Frequently Asked Questions
How many data types does JavaScript have?
JavaScript has 8 data types: String, Number, BigInt, Boolean, Undefined, Null, Symbol (7 primitives), and Object (1 reference type). Arrays, functions, and dates are all subtypes of Object.
Why does typeof null return "object"?
It's a bug from JavaScript's original 1995 implementation in Netscape Navigator. Values used a bit-tag system for type identification, and null (the null pointer, represented as 0x00) shared the same bit pattern as objects. The fix was never implemented because it would break backward compatibility with existing websites. The bug is preserved in the ECMAScript specification to this day.
What is the difference between null and undefined in JavaScript?
undefined means a variable was declared but never assigned a value, JavaScript sets it automatically. null is an intentional assignment that means "this variable has no value." Think of undefined as an accident and null as a decision.
What is type coercion in JavaScript?
Type coercion is JavaScript's automatic conversion of a value from one type to another during an operation or comparison. For example, "5" - 2 returns 3 because JavaScript coerces the string "5" to the number 5. Use === instead of == to avoid unintended coercion in comparisons.
When should I use BigInt?
Use BigInt when working with integers larger than Number. MAX_SAFE_INTEGER (9,007,199,254,740,991). Common use cases include cryptographic algorithms, high-precision timestamps, database primary keys that exceed the safe integer range, and financial calculations that require exact large integers.
JavaScript Data Types in Interviews
Data types come up in almost every JavaScript interview. Here's what interviewers are actually listening for, and the follow-up questions you should be ready to answer.
What Interviewers Want to Hear
A weak answer lists the 8 types and stops. A strong answer shows you understand why they behave the way they do.
Positive signals interviewers look for:
- You distinguish between primitive and reference types unprompted, not just listing names
- You mention that primitives are immutable and stored by value, objects are mutable and stored by reference
- You know that
typeof null === "object"is a historical bug, not intended behavior, and you can explain the workaround - You reach for
===over==and can explain why (==triggers type coercion,===does not) - You know
NaN !== NaNand useNumber.isNaN()rather thanisNaN()or=== NaN - You mention
Array.isArray()when arrays come up, rather thantypeof - You can explain optional chaining (
?.) as the safe way to access properties on potentially null values
What separates good from great: mentioning edge cases proactively. If you volunteer that null >= 0 is true but null == 0 is false, or that BigInt and Number can't be mixed in arithmetic, interviewers notice.
Common Follow-Up Questions
"What is type coercion and when does it happen?"
Explain that JavaScript automatically converts types when an operator expects a different type. Give the 1 + "2" = "12" vs 1 - "2" = -1 example to show it varies by operator. Mention that == triggers coercion but === does not.
"What's the difference between null and undefined?"
undefined is set automatically by JavaScript when a variable is declared but not assigned. null is an intentional empty value set by the developer. One is a default; the other is a decision.
"Why does typeof null return "object"?"
A bug from the 1995 Netscape implementation. Values were stored with bit-pattern type tags, and null's bit pattern (0x00) matched the object tag. The fix was never applied because it would break backward compatibility.
"How would you check if something is an array?"
Array.isArray(value) — not typeof, which returns "object" for arrays. Bonus: mention that instanceof Array can fail across iframes due to different execution contexts.
"What's the difference between primitive and reference type equality?"
Primitives compare by value ("hello" === "hello" is true). Objects compare by reference — two objects with identical content are not equal unless they point to the same memory location.
"When would you use Symbol?"
As a unique, non-enumerable property key on objects — useful in libraries to avoid naming collisions with user-defined properties, and when building iterators via Symbol.iterator.
"Can you mix BigInt and Number in arithmetic?"
No. 42n + 1 throws a TypeError. You must explicitly convert one type: 42n + BigInt(1) or Number(42n) + 1. This prevents silent precision loss.
Summary
JavaScript data types are foundational. Every value in your program is one of these 8 types, and the rules governing how they interact, coercion, comparison, copying, affect how your code behaves.
The key takeaways:
- 7 primitives: String, Number, BigInt, Boolean, Undefined, Null, Symbol, stored by value, immutable
- 1 reference type: Object (arrays, functions, dates are all objects), stored by reference
- Use
===by default to avoid implicit type coercion in comparisons typeof null === "object"is a 30-year-old bug, checkvalue!== nullexplicitlyNaN!== NaNis the only self-unequal value, useNumber. isNaN()to detect it- Objects are passed by reference, mutations inside functions affect the original