Historical Context & Motivation
Every programming language needs a way to represent different kinds of information — a person's name, their age, whether they are logged in — and JavaScript is no exception. When Brendan Eich created JavaScript in just ten days in 1995, he made a deliberate choice: the language would be dynamically typed, meaning a variable does not have to declare what kind of data it holds. This made the language approachable for beginners, but it also introduced surprises that even experienced developers still encounter today. Understanding data types is the first step toward writing predictable code.
typeof operator reports them.let and const for block-scoped variables, plus the new Symbol type. The original five types remain the core building blocks.Despite decades of evolution, the five original primitive types — number, string, boolean, null, and undefined — remain the most important to learn first. The central question this lesson addresses is: What kind of data am I working with, and how does that data type change the behavior of my expressions?
Core Principles & Definitions
A data type tells the JavaScript engine what kind of value a piece of data is — and therefore what operations make sense for it. You can add two numbers, but "adding" two booleans has a very different meaning. JavaScript groups its types into two families: primitives (simple, immutable values) and objects (complex, mutable structures). This lesson focuses on the five primitive types you will use every day.
Number
42, 3.14, -7, and the special values NaN and Infinity.String
"hello", 'world', or backtick template literals like `Hi, ${name}`. Strings are immutable — once created, individual characters cannot be changed in place.Boolean
true or false. Booleans drive every if statement and loop condition. Comparison operators like === and > always produce a boolean.Null
null to signal that it is intentionally empty. Note: typeof null returns "object" — a famous bug from 1995 that was never fixed.Undefined
Visual Explanation — The Type Landscape
typeof operator. Notice the ⚠ warning on null — it incorrectly reports as "object" due to a legacy bug.The diagram above lays out the five primitive types you will encounter in nearly every JavaScript program. The typeof operator is your go-to tool for inspecting what type a value is at runtime. You can use it like this: typeof 42 returns "number", and typeof "hello" returns "string". This is incredibly useful for debugging when your code does something unexpected.
How Types Affect Expressions
In JavaScript, the + operator behaves differently depending on the types involved. When both operands are numbers, JavaScript performs arithmetic addition. But when at least one operand is a string, JavaScript performs string concatenation — it glues the two values together as text. This behavior is called type coercion, and it is one of the most common sources of bugs for beginners.
+ operator receives two number values, it adds them normally.3 becomes "3" and the result is the string "53".+, the − operator has no string meaning, so JavaScript converts "10" to the number 10 before subtracting.true becomes 1 and false becomes 0. So true + true evaluates to 2."17" (a string), not 17 (a number). If you write age + 1, you get "171" instead of 18. Converting with Number(age) + 1 fixes the problem.Detailed Breakdown — Type Coercion & Truthiness
JavaScript does not just coerce types during arithmetic. Whenever you use a value in a boolean context — such as an if statement — the engine converts that value to true or false. Values that convert to false are called falsy, and everything else is truthy. There are exactly six falsy primitive values, and knowing them will save you from a lot of debugging.
"0" is truthy even though the number 0 is falsy.| Expression | Result | Why |
|---|---|---|
Boolean(0) | false | Zero is one of the six falsy values. |
Boolean("") | false | An empty string is falsy. |
Boolean("false") | true | Any non-empty string is truthy — even the word "false"! |
Boolean(null) | false | Null represents intentional absence, so it is falsy. |
Boolean(undefined) | false | Undefined means no value has been assigned — falsy. |
Worked Example — Debugging a Type Bug
Let's walk through a realistic scenario. You are building a simple calculator page. A user types "7" and "3" into two text inputs, then clicks an "Add" button. Your code reads these values and computes the sum. But the result displayed is "73" instead of 10. Let's figure out what went wrong and fix it.
let a = "7"; and let b = "3";. Use typeof a to confirm: it returns "string".typeof a → "string", typeof b → "string"a + b evaluates as "7" + "3". Since both operands are strings, the + operator concatenates them instead of adding."7" + "3" → "73" (string concatenation, not addition)Number(). Write Number(a) + Number(b). Now both values are type "number".Number("7") + Number("3") → 7 + 3 → 10typeof again: typeof Number(a) returns "number". The result is now correctly 10 — a number, not a string.+ operator: +"7" returns 7. So +a + +b works too, though Number() is easier to read.Comparisons — Null vs. Undefined and == vs. ===
One of the trickiest parts of JavaScript types is understanding the difference between null and undefined, and how equality operators treat different types. JavaScript has two equality operators: the loose equality operator == (which coerces types before comparing) and the strict equality operator === (which does not coerce and checks both value and type). Most professional developers strongly prefer === because it removes ambiguity.
| Expression | Result | Explanation |
|---|---|---|
null == undefined | true | Loose equality considers them equivalent — both mean "no value." |
null === undefined | false | Strict equality says they are different types. |
0 == false | true | Loose equality coerces false to 0, then compares 0 to 0. |
0 === false | false | Strict equality sees number vs. boolean — different types. |
"" == false | true | Both coerce to 0 under loose equality. |
"" === false | false | String vs. boolean — strict equality rejects. |
=== as checking that two packages are the exact same item and the same wrapping, while == rips off the wrapping first and just looks at what's inside. Using === is like being precise — it avoids mismatches that loose equality hides. As a rule, default to === unless you have a specific reason to use ==.Connection to Advanced Concepts
The five primitive types you learned here form the foundation, but JavaScript's type system goes much further. As you advance, you will encounter objects (which include arrays, functions, and custom objects), and eventually tools like TypeScript — a superset of JavaScript that adds static typing. Understanding primitive types now prepares you for all of these.
| Concept (This Lesson) | Advanced Version |
|---|---|
| Five primitive types (number, string, boolean, null, undefined) | Seven primitives in modern JS — adds Symbol (ES6) and BigInt (ES2020) for unique identifiers and large integers. |
| Dynamic typing — types checked at runtime | TypeScript adds compile-time type checking, catching type errors before code even runs. |
| Type coercion with + and == | The Abstract Equality Comparison Algorithm (ECMAScript spec) defines every coercion step formally. |
| typeof operator for checking types | instanceof, Object.prototype.toString.call(), and TypeScript type guards provide more precise type checking. |
| Falsy/truthy values | Optional chaining (?.) and nullish coalescing (??) operators give fine-grained control over null/undefined checks. |
Don't worry about memorizing these advanced topics now. The key insight is that everything you will learn about JavaScript objects, classes, and even frameworks like React traces back to understanding what type a value is and how that type influences computation. Mastering the five primitives gives you a mental model that scales.
Practice Problems
null and undefined in JavaScript. Give a real-world analogy for each."10" + 5
b) "10" - 5
c) true + 1let score; is declared but not assigned. What will each of the following log to the console?
a) console.log(typeof score);
b) console.log(score + 10);
c) console.log(score == null);
d) console.log(score === null);let fahrenheit = document.getElementById("tempInput").value;. You then compute: let celsius = (fahrenheit - 32) * 5 / 9; — If the user types 212, does this formula work correctly even though fahrenheit is a string? Explain why, and identify one related expression where it would fail.let a = "5";
let b = 3;
let c = a + b;
let d = a - b;
console.log(c, typeof c);
console.log(d, typeof d);
console.log(c == 53);
console.log(c === 53);
Predict all four console outputs. Then explain why c == 53 and c === 53 give different results, connecting your answer to at least two concepts from this lesson.Lesson Summary
JavaScript has five fundamental primitive types: number (integers, decimals, NaN, Infinity), string (text in quotes), boolean (true/false), null (intentional absence), and undefined (not yet assigned). The typeof operator reveals a value's type at runtime, which is your primary debugging tool for type-related bugs.
Types determine how expressions behave. The + operator concatenates when a string is present but adds when both sides are numbers — this is type coercion in action. Every value is either truthy or falsy when placed in a boolean context (if-statements, loops). Always prefer strict equality (===) over loose equality (==) to avoid unexpected coercion. When reading user input, explicitly convert strings to numbers using Number() before performing arithmetic.