Data types
Every value you touch in JavaScript carries a type — a label that tells the engine what kind of thing it is holding and what it is allowed to do with it. Add two numbers and you get arithmetic; add two strings and you get glue. Same +, completely different behaviour, decided entirely by type.
JavaScript has eight basic types. This chapter is the map: we name all eight and give each a sentence or two, then later chapters zoom into the ones that carry real weight. Learn the shape of the whole territory first — the details land far more easily once you know where they belong.
Here is the first surprising thing. A variable in JavaScript is not welded to a type. The same variable can hold a string now and a number a moment later, and the engine won’t complain:
// no error
let message = "hello";
message = 123456;
Languages that allow this are called dynamically typed: the values have types, but the variables that hold them do not. A box that happily accepts whatever you drop in it.
Number
let n = 123;
n = 12.345;
The number type covers both integers and floating-point numbers — there is no separate int and float here. 123 and 12.345 are the same type.
All the everyday operations live here: multiplication *, division /, addition +, subtraction -, and more. We’ll spend a whole chapter on their quirks later in Numbers.
Beyond ordinary numbers, this type includes three special numeric values: Infinity, -Infinity, and NaN. They look exotic, but you’ll meet them by accident long before you reach for them on purpose.
-
Infinityrepresents the mathematical Infinity ∞ — a value greater than any number.You get it from dividing by zero:
alert( 1 / 0 ); // InfinityOr by naming it directly:
alert( Infinity ); // Infinity -
NaNmeans “Not a Number” — the result of a maths operation that made no sense:alert( "not a number" / 2 ); // NaN, such division is erroneousNaNis sticky. Once it appears, it contaminates every operation it touches:alert( NaN + 1 ); // NaN alert( 3 * NaN ); // NaN alert( "not a number" / 2 - 1 ); // NaNSo a single
NaNburied deep in a long calculation poisons the entire result. (There is exactly one exception:NaN ** 0is1.) When a computed value comes out asNaN, treat it as a breadcrumb — somewhere upstream, a non-number slipped into the maths.
Those special values formally belong to the number type, even though NaN and Infinity aren’t numbers in the everyday sense. More on all of this in Numbers.
BigInt
The number type can’t safely hold integers larger than (253-1) — that’s 9007199254740991 — or smaller than -(253-1).
To be precise, it can store bigger values (up to about 1.7976931348623157 * 10308), but past the safe range they lose precision, because a 64-bit slot only has room for so many digits. The result is an approximation. You can watch it happen:
console.log(9007199254740991 + 1); // 9007199254740992
console.log(9007199254740991 + 2); // 9007199254740992
Add one, add two — same answer. Past the safe range, odd integers literally can’t be represented; the number type rounds to the nearest value it can hold. For most work the safe range is plenty, but cryptography and microsecond timestamps need every digit to be exact.
That’s what BigInt is for — integers of arbitrary length. You create one by appending n to an integer literal:
// the "n" at the end means it's a BigInt
const bigInt = 1234567890123456789012345678901234567890n;
BigInt is a specialist tool, so we leave the details to its own chapter, BigInt. Reach for it when — and only when — ordinary numbers start lying to you.
String
A string is text, always wrapped in quotes:
let str = "Hello";
let str2 = 'Single quotes are ok too';
let phrase = `can embed another ${str}`;
JavaScript gives you three kinds of quotes:
- Double quotes:
"Hello". - Single quotes:
'Hello'. - Backticks:
`Hello`.
Double and single quotes are interchangeable “simple” quotes — pick a style and stay consistent. Backticks are the interesting ones. They’re “extended functionality” quotes: wrap an expression in ${…} inside backticks and its value is spliced right into the text.
let name = "Maya";
// embed a variable
alert( `Hello, ${name}!` ); // Hello, Maya!
// embed an expression
alert( `the result is ${1 + 2}` ); // the result is 3
Whatever sits inside ${…} is evaluated first, and its result becomes part of the string — a variable, some arithmetic, a function call, anything. This one feature replaces a mountain of clumsy "Hello, " + name + "!" concatenation.
It only works with backticks. The other quotes take ${…} literally:
alert( "the result is ${1 + 2}" ); // the result is ${1 + 2} (double quotes do nothing)
Full details live in Strings.
Boolean (logical type)
The boolean type has exactly two values: true and false. It’s the type of yes/no, on/off, is this allowed.
let nameFieldChecked = true; // yes, name field is checked
let ageFieldChecked = false; // no, age field is not checked
You’ll rarely type true/false by hand. More often they arrive as the answer to a comparison:
let isGreater = 4 > 1;
alert( isGreater ); // true (the comparison result is "yes")
4 > 1 is a question — “is four greater than one?” — and the answer is a boolean. Every if, every loop condition, every && runs on these. We’ll dig deeper in Logical operators.
The “null” value
null is its own type, with exactly one value: null itself.
let age = null;
Coming from other languages, drop your assumptions: null here is not a null pointer or a reference to a missing object. It’s a plain value meaning “nothing”, “empty”, or “value unknown”. Writing age = null is you saying, deliberately, “we don’t know the age yet.”
The “undefined” value
undefined is also a type of its own with a single value, and it sits right next to null — but the two mean different things.
undefined means “a value was never assigned”. Declare a variable without giving it a value, and that’s what you get:
let age;
alert(age); // shows "undefined"
You can assign undefined yourself:
let age = 100;
// change the value to undefined
age = undefined;
alert(age); // "undefined"
…but don’t. The convention is: let undefined be the engine’s way of saying “nothing here yet”, and use null when you want to say “intentionally empty”. Two words, two jobs — keep them apart and your code stays readable.
Objects and Symbols
Seven of the eight types are primitive — each value holds one single thing: a number, a string, a boolean. The eighth, object, is different in kind: it holds collections — many named values bundled together, and structures far more complex than any primitive.
let user = { name: "Maya", age: 30 };
Objects are the backbone of real JavaScript, so they get their own chapter, Objects — after we’ve finished with primitives, because objects are easier to understand once the simple pieces are familiar.
The symbol type creates unique identifiers, mostly used as special object keys. We name it here for completeness and postpone it until objects make it relevant.
The typeof operator
When you need to ask a value what it is, use typeof. It returns a string naming the type — handy for quick checks and for code that must treat different types differently.
typeof undefined // "undefined"
typeof 0 // "number"
typeof 10n // "bigint"
typeof true // "boolean"
typeof "foo" // "string"
typeof Symbol("id") // "symbol"
typeof Math // "object" (1)
typeof null // "object" (2)
typeof alert // "function" (3)
The last three deserve a note:
Mathis a built-in object full of mathematical helpers (covered in Numbers). Here it’s just a stand-in for “some object”.typeof nullreturns"object"— and that is a bug in the language, baked in since JavaScript’s earliest days and frozen for backwards compatibility.nullis not an object. Don’t trusttypeofon this one; testvalue === nulldirectly.typeof alertreturns"function", even though there’s no separate “function” type — functions are objects under the hood.typeofreports"function"anyway because in practice it’s genuinely useful to know “can I call this?”
See it for yourself
Types feel abstract until you watch one value become another. Type any value below — or click a preset — and see what String(), Number(), and Boolean() make of it. Try the tricky ones: "", "0", null, []. Notice how "0" is a truthy string but converts to the number 0.
String() wraps the value in quotes-worth of text — almost anything converts cleanly.
Number() reads a numeric value. Empty/whitespace → 0, non-numeric text → NaN, true → 1, null → 0, undefined → NaN.
Boolean() asks "is this truthy?" Only 0, "", null, undefined, NaN and false are falsy — everything else is true.
The rules driving that widget — when and why JavaScript converts between types — are the whole subject of the next chapter, Type Conversions.
Summary
JavaScript has 8 basic data types.
- Seven primitive types, each holding a single value:
number— integers and floats alike, safe up to±(253-1).bigint— integers of arbitrary length.string— text; zero or more characters, with no separate single-character type.boolean—true/false.null— a type of its own whose only value,null, means “empty” or “unknown”.undefined— a type of its own whose only value,undefined, means “not assigned”.symbol— unique identifiers.
- One non-primitive type:
object— collections and complex structures.
The typeof operator reports which type a value has:
- Written
typeof x(ortypeof(x)). - Returns a string like
"string". - Returns
"object"fornull— a long-standing language bug, not the truth.
Next we focus on the primitives one by one. Once they’re second nature, objects open up easily. First stop: how JavaScript quietly converts one type into another.