Data Types & Type Coercion
title: "Data Types & Type Coercion" description: "Understand JavaScript's 8 data types, the quirks of implicit coercion, how == and === differ, and how to convert types safely and predictably." duration: "40 min" difficulty: "beginner" order: 3
Data Types & Type Coercion
JavaScript is a dynamically typed language. A variable has no fixed type — it holds whatever value you assign to it. Understanding how JavaScript categorizes and converts values is essential for avoiding the category of bugs that trips up beginners and even experienced developers.
The 8 Data Types
JavaScript has 7 primitive types and 1 object type.
Primitive Types
Primitives are immutable values. When you work with them, you work with the value directly — not a reference.
// 1. String — text, always in quotes (single, double, or backtick)
const name = "Alice";
const greeting = 'Hello';
const message = `Hi, ${name}`; // template literal — more on this below
// 2. Number — integers and decimals share one type
const age = 30;
const price = 9.99;
const negative = -42;
const scientific = 1.5e6; // 1500000
// 3. BigInt — integers too large for Number (> 2^53 - 1)
const bigNumber = 9007199254740991n; // note the 'n' suffix
// 4. Boolean — only two values
const isActive = true;
const isDeleted = false;
// 5. undefined — a variable declared but not assigned
let score;
console.log(score); // undefined
// 6. null — an intentional absence of value (you set this explicitly)
const selectedUser = null;
// 7. Symbol — a unique, immutable identifier (advanced, used for object keys)
const id = Symbol("id");
The Object Type
Everything that is not a primitive is an object. This includes plain objects, arrays, functions, dates, and regular expressions.
const user = { name: "Alice", age: 30 }; // object
const scores = [98, 87, 92]; // array (a special object)
function greet() {} // function (also a special object)
The typeof Operator
typeof returns a string describing the type of a value.
typeof "hello" // "string"
typeof 42 // "number"
typeof 9n // "bigint"
typeof true // "boolean"
typeof undefined // "undefined"
typeof Symbol() // "symbol"
typeof {} // "object"
typeof [] // "object" (arrays are objects)
typeof function(){}// "function"
The typeof null Bug
typeof null // "object"
This is a well-known bug in JavaScript that has existed since the language was created in 1995. It cannot be fixed without breaking existing code on the web. null is a primitive — it is not an object. When checking for null, use strict equality:
const value = null;
console.log(value === null); // true — correct way to check for null
console.log(typeof value === "object"); // true — misleading, don't rely on this
Implicit Type Coercion
JavaScript automatically converts types when operators are used with mismatched types. This is called implicit coercion, and it is the source of JavaScript's most infamous quirks.
The + Operator: Addition vs Concatenation
+ either adds numbers or concatenates strings. If either operand is a string, both are treated as strings.
"5" + 3 // "53" — 3 is coerced to a string
"5" + true // "5true"
1 + 2 + "3" // "33" — left to right: 1+2=3, then 3+"3"="33"
"3" + 1 + 2 // "312" — left to right: "3"+1="31", then "31"+2="312"
Arithmetic Operators: String to Number
All other arithmetic operators (-, *, /, %) coerce strings to numbers:
"5" - 3 // 2
"5" * 2 // 10
"5" - true // 4 (true coerces to 1)
"5" - false // 5 (false coerces to 0)
"5" - null // 5 (null coerces to 0)
The Famous Weird Table
These are real JavaScript expressions you can run in any browser console:
[] + [] // "" — two arrays coerce to empty strings, concatenated
[] + {} // "[object Object]"
{} + [] // 0 — {} is parsed as an empty block, not an object; +[] is 0
true + true // 2
true + false // 1
[] == false // true
null == undefined // true
null == false // false (null only loosely equals undefined)
NaN == NaN // false (NaN is not equal to anything, including itself)
These results exist because of coercion rules, and they are why professional JavaScript relies on strict equality.
== vs ===
==(loose equality) — coerces types before comparing===(strict equality) — compares value and type, no coercion
0 == false // true — false coerces to 0
0 === false // false — different types
"" == false // true
"" === false // false
null == undefined // true
null === undefined // false
1 == "1" // true
1 === "1" // false
Always use === in professional code. The only legitimate use of == is checking for null and undefined simultaneously: value == null catches both.
NaN: Not a Number
NaN is a number type value that represents an invalid numeric operation.
typeof NaN // "number" — confusingly, NaN is of type number
"hello" * 2 // NaN
parseInt("abc") // NaN
0 / 0 // NaN
NaN is the only value in JavaScript that is not equal to itself. Use Number.isNaN() to check for it:
NaN === NaN // false
isNaN("hello") // true — misleading: converts to number first, then checks
Number.isNaN("hello") // false — correct: only true if value is actually NaN
Number.isNaN(NaN) // true
Prefer Number.isNaN() over the global isNaN().
Explicit Type Conversion
When you need to convert types, do it explicitly so the intent is clear.
// To Number
Number("42") // 42
Number("3.14") // 3.14
Number("") // 0
Number("hello") // NaN
Number(true) // 1
Number(false) // 0
Number(null) // 0
Number(undefined) // NaN
parseInt("42px") // 42 — parses leading integer from a string
parseFloat("3.5kg") // 3.5
// To String
String(42) // "42"
String(true) // "true"
String(null) // "null"
String(undefined)// "undefined"
(42).toString() // "42"
// To Boolean
Boolean(0) // false
Boolean("") // false
Boolean(null) // false
Boolean(undefined) // false
Boolean(NaN) // false
Boolean(false) // false
// Everything else is true:
Boolean(1) // true
Boolean("hello") // true
Boolean([]) // true — empty array is truthy!
Boolean({}) // true — empty object is truthy!
Truthy and Falsy Values
In a boolean context (like an if condition), every value in JavaScript is either truthy or falsy.
The 6 falsy values:
false, 0, "", null, undefined, NaN
Every other value is truthy, including "0", [], and {}.
if ("") {
console.log("falsy — this won't run");
}
if ("hello") {
console.log("truthy — this runs"); // "truthy — this runs"
}
if ([]) {
console.log("empty array is truthy — this runs"); // runs
}
This is used in practice to check whether a value exists before using it:
const username = getUserInput(); // might return "" or a name
if (username) {
console.log(`Welcome, ${username}`);
} else {
console.log("Please enter a username");
}
Template Literals
Template literals (backtick strings) allow embedded expressions and multi-line strings without concatenation:
const product = "keyboard";
const price = 79.99;
// Old way — hard to read
const msg1 = "The " + product + " costs $" + price;
// Template literal — clean and readable
const msg2 = `The ${product} costs $${price}`;
console.log(msg2); // "The keyboard costs $79.99"
// Multi-line
const html = `
<div class="card">
<h2>${product}</h2>
<p>$${price}</p>
</div>
`;
Any valid JavaScript expression can go inside ${}:
const a = 10;
const b = 5;
console.log(`${a} + ${b} = ${a + b}`); // "10 + 5 = 15"
console.log(`${a > b ? "greater" : "lesser"}`); // "greater"
Key Takeaways
- JavaScript has 7 primitive types and 1 object type. Primitives are values; objects are references.
typeof nullreturns"object"— this is a known bug. Use=== nullto check for null.- Implicit coercion with
+concatenates if any operand is a string; other operators convert to numbers. - Always use
===for comparisons. Avoid==except for thevalue == nullpattern. - Use
Number.isNaN()notisNaN(). - The 6 falsy values are:
false,0,"",null,undefined,NaN. Everything else is truthy. - Use template literals for string construction — they are cleaner and more readable.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises