Type Conversion & Coercion
JavaScript is happy to convert values between types — sometimes when you ask, sometimes silently as part of an operator. The explicit version is conversion; the implicit version is coercion. Both are useful, both have sharp edges, and untangling them is one of the rites of passage in learning the language.
Explicit conversion
Call the built-in constructors as plain functions (no new) to convert a value.
Number("42"); // 42
Number("42px"); // NaN — entire string must be a number
Number(""); // 0 (!)
Number(true); // 1
Number(false); // 0
Number(null); // 0
Number(undefined); // NaN
String(42); // "42"
String(true); // "true"
String(null); // "null"
String([1, 2, 3]); // "1,2,3"
Boolean(0); // false
Boolean(""); // false
Boolean("false"); // true — non-empty string is truthy
Boolean([]); // true — empty array is truthy
Boolean({}); // true — empty object is truthyImplicit coercion
Operators that expect a specific type will convert their operands first. The rules are stable but unintuitive in places.
// + with a string → string concatenation
"3" + 4; // "34"
"3" + true; // "3true"
[] + []; // ""
[] + {}; // "[object Object]"
// Other arithmetic → number
"3" - 1; // 2
"3" * "4"; // 12
"6" / "2"; // 3
// Comparison with a string and a number → number
"5" > 3; // true
"10" > "9"; // false — string comparison is lexicographic ("1" < "9")
// Boolean context → boolean
if ("0") { /* runs — non-empty string is truthy */ }
if (0) { /* doesn't run */ }== vs ===
== is loose equality: if the two values are different types, it coerces one or both and tries again. === is strict equality: same type, same value, no coercion.
0 == ""; // true 0 == false; // true null == undefined;// true 1 == "1"; // true [] == false; // true [1] == 1; // true 0 === ""; // false 1 === "1"; // false null === undefined; // false
The full == algorithm spans three pages of the spec. The short version: nobody remembers all the rules, and most bugs in this area come from accidental loose equality.
Truthy and falsy
A value is falsy if it coerces to false, otherwise truthy. There are exactly eight falsy values in JavaScript — everything else is truthy.
The complete falsy list
false 0 -0 0n // bigint zero "" // empty string null undefined NaN
That means an empty array [], an empty object {} and the string "0" are all truthy. People get caught by this regularly.
if ([]) console.log("array"); // runs
if ({}) console.log("object"); // runs
if ("0") console.log("zero"); // runs
const items = [];
if (items) console.log("has items?"); // runs — wrong test
if (items.length) console.log("has items?"); // doesn't run — correct testThe common gotchas
// "0" is truthy, but Boolean("0") is true, AND "0" == false is true
"0" == false; // true
Boolean("0"); // true
// Adding numbers received from inputs
const a = "3", b = "4";
a + b; // "34"
Number(a) + Number(b); // 7
+a + +b; // 7 (terse)
// Date arithmetic is fine — Date coerces to number via valueOf
new Date(2026, 0) - new Date(2025, 0); // milliseconds between
// NaN propagates
1 + NaN; // NaN
Number("abc") + 1; // NaN
// Empty array tricks
+[]; // 0
+[1]; // 1
+[1, 2]; // NaN
+""; // 0Object.is — strict equality plus
Object.is is almost identical to === with two differences:
Object.is(NaN, NaN)istrue— useful when you specifically want NaN-to-NaN to match.Object.is(+0, -0)isfalse—===thinks they're equal.
Object.is(NaN, NaN); // true — === would be false Object.is(+0, -0); // false — === would be true Object.is(2, 2); // true
You'll rarely write this in app code, but React's reconciliation uses Object.is, and so do other libraries that need a defensible notion of "same value".
Practical guidance
Convert explicitly at boundaries — when you receive user input, when you serialise data, when you cross from one system to another.
Use
===/!==by default. Reach for==only when you really want the loose semantics (usuallyx == null).Test arrays and objects on
.lengthor specific properties, not on truthiness.When you want a clean boolean, use
Boolean(value)or!!value.When parsing numeric input,
Number(value)is strict,parseInt/parseFloatare lenient — pick deliberately.