JavaScript Data Types: A Complete Beginner Guide
Master all JavaScript data types including primitives and objects. Learn how each type behaves, when to use them, and how to check types with typeof in practical, real-world code examples.
Every value in JavaScript belongs to a specific data type. Understanding these types is fundamental to writing code that behaves the way you expect. JavaScript has eight built-in data types: seven primitives and one non-primitive type (objects). This guide walks through each one with practical examples, explains how type checking works, and shows you how data types affect everyday operations like comparisons, function arguments, and storage.
If you are still getting comfortable with JavaScript variables, start there first. This article assumes you know how to declare variables with let and const.
The Eight JavaScript Data Types
JavaScript data types fall into two categories: primitive types and reference types. Primitives hold simple, immutable values. Reference types hold complex structures that can change.
| Category | Type | Example | typeof Result |
|---|---|---|---|
| Primitive | String | "hello" | "string" |
| Primitive | Number | 42, 3.14 | "number" |
| Primitive | BigInt | 9007199254740991n | "bigint" |
| Primitive | Boolean | true, false | "boolean" |
| Primitive | Undefined | undefined | "undefined" |
| Primitive | Null | null | "object" (historic bug) |
| Primitive | Symbol | Symbol("id") | "symbol" |
| Reference | Object | {}, [], function(){} | "object" or "function" |
Why null Returns 'object'
The typeof null === "object" result is a well-known bug from JavaScript's first implementation in 1995. It was never fixed because changing it would break billions of lines of existing code. Always check for null explicitly with value === null.
Primitive Types in Detail
String
Strings represent text data. You can create them with single quotes, double quotes, or backtick template literals.
const firstName = "Ada";
const lastName = 'Lovelace';
const greeting = `Hello, ${firstName} ${lastName}!`;
console.log(greeting); // "Hello, Ada Lovelace!"
console.log(typeof greeting); // "string"
console.log(greeting.length); // 20Strings are immutable in JavaScript. Every string operation creates a new string rather than modifying the original.
const original = "JavaScript";
const upper = original.toUpperCase();
console.log(original); // "JavaScript" (unchanged)
console.log(upper); // "JAVASCRIPT" (new string)Number
JavaScript uses a single Number type for both integers and floating-point values. It follows the IEEE 754 double-precision 64-bit format.
const age = 25;
const price = 19.99;
const negative = -42;
const scientific = 2.998e8; // 299,800,000
console.log(typeof age); // "number"
console.log(typeof price); // "number"The Number type has three special values you should know:
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log("text" * 2); // NaN (Not a Number)
console.log(typeof NaN); // "number" (yes, NaN is a number type)The safe integer range extends from -(2^53 - 1) to 2^53 - 1. Beyond these limits, precision is lost.
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(9007199254740991 + 1); // 9007199254740992
console.log(9007199254740991 + 2); // 9007199254740992 (wrong!)BigInt
When you need integers larger than Number.MAX_SAFE_INTEGER, use BigInt. Add an n suffix to any integer literal.
const largeNumber = 9007199254740991n;
const anotherBig = BigInt("123456789012345678901234567890");
console.log(largeNumber + 1n); // 9007199254740992n (correct!)
console.log(typeof largeNumber); // "bigint"BigInt cannot be mixed with regular numbers in arithmetic operations. You must convert explicitly.
// This throws: TypeError: Cannot mix BigInt and other types
// const result = 10n + 5;
const result = 10n + BigInt(5); // 15nBoolean
Booleans represent logical values: true or false. They drive every conditional and loop in JavaScript.
const isLoggedIn = true;
const hasPermission = false;
console.log(typeof isLoggedIn); // "boolean"Every JavaScript value can be converted to a boolean. Values that become false are called "falsy," and everything else is "truthy."
| Falsy Values | Truthy Values (examples) |
|---|---|
false | true |
0, -0, 0n | 1, -1, 3.14 |
"" (empty string) | "hello", " " (space) |
null | {} (empty object) |
undefined | [] (empty array) |
NaN | "0" (string zero) |
Undefined
A variable that has been declared but not assigned a value holds undefined. Functions that do not explicitly return a value also return undefined.
let username;
console.log(username); // undefined
console.log(typeof username); // "undefined"
function doNothing() {}
console.log(doNothing()); // undefinedNull
null represents an intentional absence of any value. Unlike undefined (which means "not yet assigned"), null means "explicitly empty."
let selectedUser = null; // No user selected yet
console.log(selectedUser); // null
console.log(typeof selectedUser); // "object" (the historic bug)Use null when you want to deliberately clear a variable or signal "no value here."
Symbol
Symbols are unique, immutable identifiers introduced in ES2015. They are primarily used as object property keys that cannot collide with other keys.
const id = Symbol("userId");
const anotherId = Symbol("userId");
console.log(id === anotherId); // false (every Symbol is unique)
console.log(typeof id); // "symbol"
const user = {
[id]: 12345,
name: "Ada",
};
console.log(user[id]); // 12345Reference Types: Objects
Everything that is not a primitive is an object. This includes plain objects, arrays, functions, dates, regular expressions, and more.
const user = { name: "Ada", age: 25 };
const scores = [95, 87, 92, 88];
const greet = function (name) {
return `Hello, ${name}!`;
};
console.log(typeof user); // "object"
console.log(typeof scores); // "object"
console.log(typeof greet); // "function"
console.log(Array.isArray(scores)); // trueThe key difference between primitives and objects is that objects are stored by reference. When you assign an object to another variable, both variables point to the same data in memory.
const original = { name: "Ada", role: "engineer" };
const copy = original;
copy.role = "architect";
console.log(original.role); // "architect" (both point to the same object!)For a deeper exploration of how this affects your code, check the primitive vs reference types guide.
Type Checking with typeof
The typeof operator is the primary way to check data types at runtime. It returns a string indicating the type.
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (bug, check with === null)
console.log(typeof Symbol("x")); // "symbol"
console.log(typeof 10n); // "bigint"
console.log(typeof {}); // "object"
console.log(typeof []); // "object" (use Array.isArray())
console.log(typeof function(){}); // "function"For robust type checking, combine typeof with specific checks:
function getType(value) {
if (value === null) return "null";
if (Array.isArray(value)) return "array";
return typeof value;
}
console.log(getType(null)); // "null"
console.log(getType([1, 2, 3])); // "array"
console.log(getType({ a: 1 })); // "object"
console.log(getType("text")); // "string"Best Practices
Write Type-Safe JavaScript
These practices help you avoid the most common type-related bugs in JavaScript projects.
Use strict equality (===) for comparisons. The loose equality operator (==) performs type coercion, which can produce surprising results like 0 == "" returning true. Always use === to compare both value and type.
Check for null and undefined separately. Since typeof null returns "object", never rely on typeof alone to detect null. Use value === null for null checks and typeof value === "undefined" for undefined checks.
Use Array.isArray() for array detection. Since typeof [] returns "object", the only reliable way to check for arrays is Array.isArray(value).
Initialize variables with the correct type. Declare variables with the value type you intend to use. If you plan to store a number, initialize with 0 or NaN, not null or "". This makes your code's intent clear.
Prefer template literals for string building. Instead of concatenating strings with +, use backtick template literals. They handle type conversion automatically and are easier to read.
Common Mistakes and How to Avoid Them
Type-Related Pitfalls
These mistakes cause subtle bugs that are hard to track down in larger codebases.
Confusing null and undefined. Both represent "no value," but they have different semantics. undefined means a variable was declared but not assigned. null is an intentional empty value. Treating them interchangeably leads to inconsistent behavior in your APIs and functions.
Assuming typeof always identifies the type correctly. The typeof operator has quirks: typeof null is "object", typeof [] is "object", and typeof NaN is "number". Always use targeted checks for these edge cases.
Performing arithmetic on mixed types without conversion. JavaScript silently coerces types during arithmetic operations, which produces unexpected results like "5" + 3 returning "53" (string concatenation) instead of 8.
Comparing BigInt with Number using ===. Strict equality between BigInt and Number always returns false, even when the values are mathematically equal. Use loose equality (==) or convert explicitly.
console.log(10n === 10); // false
console.log(10n == 10); // true
console.log(10n === BigInt(10)); // trueForgetting that NaN is not equal to itself. The only value in JavaScript where x !== x is NaN. Use Number.isNaN(value) to check for NaN reliably.
Next Steps
Explore [dynamic typing](/tutorials/programming-languages/javascript/what-are-dynamic-data-types-in-javascript)
Learn how JavaScript's dynamic type system works and why variables can hold any type at any time in the dynamic data types guide.
Understand memory storage
Discover how JavaScript stores primitive values on the stack and objects on the heap, and why this matters for performance and debugging.
Learn type conversion
Master implicit and explicit type conversion to understand how JavaScript automatically converts types during operations.
Practice with operators
Apply your data type knowledge to arithmetic, comparison, and logical operators with real examples.
Rune AI
Key Insights
- Eight types total: seven primitives (String, Number, BigInt, Boolean, Undefined, Null, Symbol) plus Object
- Primitives are immutable: operations on primitives create new values rather than modifying the original
- typeof has quirks:
typeof nullreturns"object"andtypeof []returns"object", so use targeted checks - Objects store by reference: assigning an object to a new variable creates a shared pointer, not a copy
- Use strict equality: always prefer
===over==to avoid implicit type coercion surprises
Frequently Asked Questions
How many data types does JavaScript have?
What is the difference between null and undefined in JavaScript?
Why does typeof null return "object" in JavaScript?
When should I use BigInt instead of Number in JavaScript?
Is JavaScript a strongly typed or weakly typed language?
Conclusion
JavaScript's eight data types form the foundation of every program you write, from simple scripts to complex web applications. Understanding the distinction between primitives and objects, knowing the quirks of typeof, and recognizing how type coercion works will save you hours of debugging. The most impactful habit is using strict equality (===) and targeted type checks (Array.isArray, Number.isNaN, === null) instead of relying on JavaScript's automatic type conversions.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.