JavaScript has eight data types โ seven primitive types and one complex type (object). Understanding types is fundamental to JavaScript because the language is dynamically typed โ variables can hold any type, and types can change at runtime. This flexibility is powerful but also a source of bugs if you do not understand how JavaScript handles types behind the scenes. In this lesson you will learn all eight types and how to detect and work with them reliably.
The Eight JavaScript Data Types
| Type | Category | Example Values |
|---|---|---|
string |
Primitive | 'hello', "world", `template` |
number |
Primitive | 42, 3.14, -7, Infinity, NaN |
bigint |
Primitive | 9007199254740991n โ integers beyond Number limit |
boolean |
Primitive | true, false |
undefined |
Primitive | undefined โ declared but not yet assigned |
null |
Primitive | null โ intentional absence of a value |
symbol |
Primitive | Symbol('id') โ unique, immutable identifier |
object |
Complex | { name: 'Alice' }, [1,2,3], new Date(), null* |
Checking Types with typeof
| Expression | typeof Result | Notes |
|---|---|---|
typeof 'hello' |
'string' |
|
typeof 42 |
'number' |
Also: NaN, Infinity |
typeof true |
'boolean' |
|
typeof undefined |
'undefined' |
|
typeof null |
'object' |
โ ๏ธ Historic bug โ null is NOT an object |
typeof {} |
'object' |
Use Array.isArray() to distinguish arrays |
typeof [] |
'object' |
Arrays are objects โ use Array.isArray() |
typeof function(){} |
'function' |
Functions are objects but get their own typeof |
Truthy and Falsy Values
| Falsy (evaluates to false) | Truthy (evaluates to true) |
|---|---|
false |
Everything not on the falsy list |
0, -0, 0n |
1, -1, any non-zero number |
'', "", `` (empty string) |
'hello', ' ' (space is truthy!) |
null |
[] empty array โ truthy! |
undefined |
{} empty object โ truthy! |
NaN |
'0' string zero โ truthy! |
typeof null === 'object' is one of JavaScript’s most famous bugs โ introduced in 1995 and never fixed because fixing it would break the entire internet. To correctly check for null, always use strict equality: value === null. Never use typeof value === 'null' โ that will always be false.null and undefined: undefined means a variable was declared but never assigned a value โ it is the JavaScript runtime saying “there is nothing here yet.” null is an intentional value you assign to mean “empty” or “no value” โ it is the programmer saying “I deliberately set this to nothing.” Use null to clear a value; never assign undefined manually.[]) and empty objects ({}) are truthy โ they have a value, just an empty one. This surprises many beginners: if ([]) { console.log('runs!') } will log “runs!” To check if an array is empty, check arr.length === 0. To check if an object has no keys, use Object.keys(obj).length === 0.Basic Example
// โโ The 7 primitive types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const greeting = 'Hello, World!'; // string
const age = 28; // number
const price = 9.99; // number (no separate float type)
const isActive = true; // boolean
const nothing = null; // null
let notDefined; // undefined (no assignment)
const bigNum = 9007199254740992n; // bigint (note the n suffix)
const uid = Symbol('userId'); // symbol โ always unique
// โโ typeof detection โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
console.log(typeof greeting); // 'string'
console.log(typeof age); // 'number'
console.log(typeof isActive); // 'boolean'
console.log(typeof nothing); // 'object' โ the famous bug (it IS null)
console.log(typeof notDefined); // 'undefined'
console.log(typeof bigNum); // 'bigint'
console.log(typeof uid); // 'symbol'
console.log(typeof {}); // 'object'
console.log(typeof []); // 'object' โ use Array.isArray()
// Correct null check
console.log(nothing === null); // true โ
console.log(Array.isArray([])); // true โ
// โโ Special number values โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(0 / 0); // NaN
console.log(Number.isNaN(0/0)); // true โ use Number.isNaN(), not isNaN()
// โโ Truthy / falsy in action โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const values = [0, '', null, undefined, NaN, false, [], {}, 'hello', 42];
values.forEach(v => {
console.log(`${String(v).padEnd(10)} โ ${v ? 'truthy' : 'falsy'}`);
});
// 0 โ falsy
// '' โ falsy
// null โ falsy
// undefined โ falsy
// NaN โ falsy
// false โ falsy
// [] โ truthy โ surprises beginners!
// {} โ truthy โ surprises beginners!
// hello โ truthy
// 42 โ truthy
// โโ Dynamic typing โ types can change โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
let dynamic = 42;
console.log(typeof dynamic); // 'number'
dynamic = 'now a string';
console.log(typeof dynamic); // 'string'
dynamic = { key: 'value' };
console.log(typeof dynamic); // 'object'
How It Works
Step 1 โ Primitives Are Stored by Value
When you assign a primitive to a variable, the actual value is stored directly in the variable. Copying a primitive copies the value: let b = a creates a completely independent copy. Changing b has no effect on a.
Step 2 โ Objects Are Stored by Reference
Objects (including arrays and functions) are stored by reference โ the variable holds a pointer to the location in memory where the object lives. Copying an object variable copies the reference, not the object. Two variables pointing to the same object means changing one changes the other.
Step 3 โ NaN Is a Number Type
NaN stands for “Not a Number” โ but typeof NaN is 'number'. It is the result of invalid arithmetic: 0/0, parseInt('hello'), Math.sqrt(-1). NaN is the only value in JavaScript not equal to itself: NaN === NaN is false. Always use Number.isNaN() to check for it.
Step 4 โ JavaScript Is Dynamically Typed
Unlike Java or TypeScript, JavaScript does not enforce types on variables. A variable can hold a string, then a number, then an object โ the type is determined at runtime by whatever value is currently stored. This is convenient but requires careful attention to avoid type-related bugs.
Step 5 โ Falsy Values Are the Six Exceptions
In a boolean context (like an if condition), JavaScript converts any value to true or false. Only six values are falsy: false, 0, '', null, undefined, and NaN. Everything else โ including empty arrays and empty objects โ is truthy.
Real-World Example: Form Input Validator
// form-validator.js
function validateField(name, value) {
// Type guard โ ensure we have a string
if (typeof value !== 'string') {
return { valid: false, error: `${name} must be a string` };
}
const trimmed = value.trim();
// Falsy check โ empty string is falsy
if (!trimmed) {
return { valid: false, error: `${name} is required` };
}
return { valid: true, value: trimmed };
}
function validateAge(value) {
const num = Number(value);
// NaN check
if (Number.isNaN(num)) {
return { valid: false, error: 'Age must be a number' };
}
if (!Number.isInteger(num) || num < 0 || num > 120) {
return { valid: false, error: 'Age must be a whole number between 0 and 120' };
}
return { valid: true, value: num };
}
function validateForm(data) {
const errors = [];
// null / undefined check for required fields
if (data.name == null) { // catches both null and undefined
errors.push('name field is missing');
} else {
const nameResult = validateField('Name', data.name);
if (!nameResult.valid) errors.push(nameResult.error);
}
const ageResult = validateAge(data.age);
if (!ageResult.valid) errors.push(ageResult.error);
return { valid: errors.length === 0, errors };
}
// Tests
console.log(validateForm({ name: 'Alice', age: '28' })); // valid: true
console.log(validateForm({ name: '', age: '28' })); // Name is required
console.log(validateForm({ name: 'Bob', age: 'abc' })); // Age must be a number
console.log(validateForm({ name: null, age: '25' })); // name field is missing
console.log(validateForm({ age: '25' })); // name field is missing
Common Mistakes
Mistake 1 โ Using typeof to check for null
โ Wrong โ typeof null returns ‘object’, not ‘null’:
if (typeof value === 'null') { ... } // never true โ typeof null is 'object'
โ Correct โ use strict equality for null checks:
if (value === null) { ... } // correct
if (value == null) { ... } // catches both null AND undefined
Mistake 2 โ Treating empty array/object as falsy
โ Wrong โ [] and {} are truthy, so this condition always runs:
const items = [];
if (!items) {
console.log('No items'); // Never runs โ [] is truthy!
}
โ Correct โ check the length for arrays, Object.keys() for objects:
if (items.length === 0) { console.log('No items'); } // correct
Mistake 3 โ Using isNaN() instead of Number.isNaN()
โ Wrong โ global isNaN() coerces its argument first, giving false positives:
isNaN('hello') // true โ 'hello' coerces to NaN first
isNaN(undefined) // true โ undefined coerces to NaN
โ Correct โ Number.isNaN() only returns true for actual NaN:
Number.isNaN('hello') // false โ 'hello' is a string, not NaN
Number.isNaN(NaN) // true โ this is actual NaN
Quick Reference
| Type | typeof | Check For It With |
|---|---|---|
| string | 'string' |
typeof x === 'string' |
| number | 'number' |
typeof x === 'number' && !Number.isNaN(x) |
| boolean | 'boolean' |
typeof x === 'boolean' |
| undefined | 'undefined' |
x === undefined or typeof x === 'undefined' |
| null | 'object' โ ๏ธ |
x === null |
| array | 'object' |
Array.isArray(x) |
| object (plain) | 'object' |
typeof x === 'object' && x !== null |
| NaN | 'number' โ ๏ธ |
Number.isNaN(x) |