An if in JavaScript does not expect a boolean. It accepts any value and converts it to true or false on its own. That feels convenient early on, and it is the source of an entire family of bugs that are hard to spot.
The classic case: a counter holding 0 vanishes from the screen, even though 0 is a perfectly valid value. Understanding truthy and falsy means no longer being caught out by that kind of disappearance.
Definition
A value is falsy when the language treats it as false in a boolean context, and truthy otherwise. The list of falsy values is short and closed: everything else is truthy.
| Falsy value | What it represents |
|---|---|
false | The boolean false itself |
0 and -0 | Numeric zero |
0n | Zero as a BigInt |
"" | The empty string |
null | A deliberate absence of value |
undefined | A value never set |
NaN | The result of an impossible calculation |
There are no others. An empty array is truthy, an empty object is truthy, the string "0" is truthy, and so is the string "false".
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean([])); // true, an empty array is still an object
console.log(Boolean({})); // true
console.log(Boolean("0")); // true, it is a non-empty stringWhere it turns against you
The trap never shows up on clear-cut values. It shows up when a legitimate value happens to be falsy.
- A counter at zero.
if (count)skips the 0 case, which is nevertheless a valid answer. - An empty form field. The empty string is falsy, so it cannot be told apart from a missing field if you only test for presence.
- A badly chosen fallback.
price || 49replaces a price of 0 with 49, which was never the intention.
That last case is solved by Nullish coalescing (??), which only fires on null and undefined and lets 0 and the empty string through untouched.
Testing cleanly
The practical rule is one distinction: ask yourself whether you are testing for presence or for a value.
const stock = 0;
if (stock) console.log("never printed");
if (stock !== undefined) console.log("stock has been set");
if (stock > 0) console.log("seats are left");The short condition stays perfectly legitimate on things that really are optional. It becomes dangerous as soon as 0 or the empty string belong to the expected values. For an explicit comparison, always reach for Strict equality (===).
Frequently asked questions
Why is an empty array truthy?
Because the conversion to boolean never inspects the contents, only the type. Every object, and an array is one, is truthy without exception. To test for an empty array you have to go through its length with list.length === 0, which also reads more clearly later.
How do I convert a value to a boolean explicitly?
Two spellings exist and give exactly the same result: Boolean(value) and the double negation !!value. The first reads better, the second is shorter and very widespread. The Boolean entry covers both and the cases where the conversion is genuinely useful.
NaN is falsy, so why is it so hard to detect?
Because NaN equals nothing, not even itself: NaN === NaN is false. The only reliable test is Number.isNaN(value). This is a direct consequence of silent Coercion (type conversion), which produces that NaN without ever raising an error.