JavaScript is flexible, sometimes too flexible. When you mix different types in operations, JavaScript doesn't throw errors; it tries to make sense of what you meant by converting values automatically. This automatic conversion is called type coercionWhat is type coercion?JavaScript automatically converting a value from one type to another during an operation, like turning a string into a number for subtraction., and it's responsible for some of JavaScript's most infamous "wat" moments.
Implicit coercion: JavaScript guesses
Imagine asking someone "What's 5 plus 3?" and they answer "53" because they treated your numbers as text. That's essentially what JavaScript does:
// The + operator with strings
console.log("5" + 3); // "53" (string concatenation)
console.log(5 + "3"); // "53" (string wins)
console.log("5" + "3"); // "53" (both strings)
// But other operators convert to numbers
console.log("5" - 3); // 2 (numeric subtraction)
console.log("5" * 3); // 15 (numeric multiplication)
console.log("5" / 3); // 1.666... (numeric division)
console.log("5" % 3); // 2 (numeric modulo)Why the inconsistency? The + operator serves double duty, addition for numbers, concatenation for strings. When one operand is a string, JavaScript assumes you want concatenation. Other arithmetic operators only make sense with numbers, so JavaScript converts strings to numbers.
if (userInput == 42) instead of if (Number(userInput) === 42), or build price calculations directly from form values without converting strings to numbers first. The code "works" in the happy path but breaks with edge cases like "0", empty strings, or null. Never trust AI-generated arithmetic on values that might be strings, always convert explicitly.Comparison coercion
This is where things get really weird:
console.log("5" == 5); // true (!!!)
console.log(true == 1); // true (!!!)
console.log(false == 0); // true (!!!)
console.log("" == false); // true (!!!)
console.log(null == undefined); // true (!!!)
console.log([1] == "1"); // true (!!!)The loose equality operator (==) performs type coercionWhat is type coercion?JavaScript automatically converting a value from one type to another during an operation, like turning a string into a number for subtraction. before comparison. The rules are complex and sometimes surprising, that's why experienced JavaScript developers pretend it doesn't exist.
The null and undefined gotchas
console.log(null == undefined); // true
console.log(null === undefined); // false
console.log(null == 0); // false (surprisingly!)
console.log(null >= 0); // true (coerces null to 0!)Yes, null >= 0 is true while null == 0 is false. This happens because relational operators (>, <, >=, <=) coerce null to 0, but equality operators treat null as special.
"5" === 5 is false because a string is not a number, even when they look similar.Explicit conversion: You take control
Instead of letting JavaScript guess, tell it exactly what you want:
Converting to numbers
// The Number() function
console.log(Number("42")); // 42
console.log(Number("42.5")); // 42.5
console.log(Number("")); // 0 (empty string becomes 0)
console.log(Number("hello")); // NaN (Not a Number)
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaNConverting to strings
// The String() function
console.log(String(42)); // "42"
console.log(String(true)); // "true"
console.log(String(null)); // "null"
console.log(String(undefined)); // "undefined"
console.log(String([1, 2, 3])); // "1,2,3"
// Alternative: toString() method
console.log((42).toString()); // "42"
console.log(true.toString()); // "true"Converting to booleans
// The Boolean() function
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
console.log(Boolean("hello")); // true
console.log(Boolean("")); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined));// false
console.log(Boolean([])); // true (empty array is truthy!)
console.log(Boolean({})); // true (empty object is truthy!)Truthy and falsy values
In boolean contexts (like if statements or logical operators), values are coerced to true or false. Knowing which values become which prevents bugs.
The six falsy values
These always become false:
| Value | Why it's falsy |
|---|---|
false | The boolean itself |
0 | Zero |
"" | Empty string |
null | Intentional absence |
undefined | Uninitialized |
NaN | Invalid number |
Everything else is truthy
// These might surprise you
console.log(Boolean("0")); // true (non-empty string)
console.log(Boolean("false")); // true (non-empty string)
console.log(Boolean([])); // true (empty array)
console.log(Boolean({})); // true (empty object)
console.log(Boolean(function(){})); // true (functions are objects)Practical truthy/falsyWhat is truthy/falsy?How JavaScript treats non-boolean values in conditions: some values act as false (0, empty string, null, undefined, NaN) and everything else acts as true. patterns
// Check if string has content
const input = "";
if (input) {
console.log("Has content");
} else {
console.log("Empty"); // This runs
}
// But be careful with numbers!
const count = 0;
if (count) {
console.log("Has items");
} else {
console.log("Empty or zero"); // This runs (0 is falsy!)
}
// Better check for numbers
if (count > 0) {
console.log("Has items");
}Practical conversion examples
// Form input handling
const userAge = "25";
const age = Number(userAge);
if (age >= 18) {
console.log("Adult");
}
// Safe conversion with fallback
const priceInput = "abc";
const price = Number(priceInput) || 0;
console.log(price); // 0 (because NaN || 0 returns 0)
// String concatenation safety
const items = 5;
const message = "You have " + String(items) + " items";
// Or better: `You have ${items} items`Quick reference
| Conversion | Method | Watch out for |
|---|---|---|
| To number | Number(x) | Number("") is 0, Number("hello") is NaN |
| To string | String(x) | String(null) is "null", not "" |
| To boolean | Boolean(x) | Boolean([]) is true, Boolean("") is false |
| Check NaN | Number.isNaN(x) | isNaN("hello") is true (coerces first) |
| Strict compare | === / !== | Never coerces, always safe |
// Implicit coercion (often surprising)
console.log("5" + 3); // "53" (string wins)
console.log("5", 3); // 2 (number math)
console.log("5" == 5); // true (coerced equality)
console.log("5" === 5); // false (strict equality)
console.log(true + true); // 2 (booleans become 1 + 1)
// Explicit conversion (predictable)
console.log(Number("42")); // 42
console.log(String(42)); // "42"
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
// Truthy vs falsy
console.log(Boolean("0")); // true (non-empty string)
console.log(Boolean([])); // true (empty array)
console.log(Boolean("")); // false (empty string)
console.log(Boolean(null)); // false
// Safe form handling
const userInput = "25";
const age = Number(userInput);
if (!isNaN(age)) {
console.log(`User is ${age} years old`);
}