Truthy and Falsy Values
Memorize JS falsy list, avoid || default traps with 0 and '', and prefer Boolean() / ?? for intent-clear checks.
- javascript
- truthy-and
In boolean contexts (if, while, &&, ||, ternary), values coerce to true or false. Falsy values are a short fixed list; everything else is truthy — including [], {}, and "0".
The falsy list (memorize)
false
0
-0
0n // BigInt zero
'' // empty string
null
undefined
NaN
That’s it. No, empty arrays are not falsy.
if ([]) console.log('runs'); // truthy
if ({}) console.log('runs'); // truthy
if ('0') console.log('runs'); // truthy string
if (new Boolean(false)) console.log('runs'); // object wrapper is truthy!
Coercion helpers
Boolean(x);
!!x; // common idiom
Prefer explicit checks when zero/empty string are valid:
// BAD for counts
const count = input || 10; // 0 becomes 10
// GOOD
const count = input ?? 10;
// or
const count = input === undefined || input === null ? 10 : input;
&& and || return values, not booleans
0 || 'default'; // 'default'
2 || 'default'; // 2
1 && 2 && 3; // 3
1 && 0 && 3; // 0
Short-circuit:
user && user.name;
// today: user?.name
Truthy checks that lie
const items = [];
if (items) {
// always true even when empty
}
if (items.length) {
// empty check
}
const map = new Map();
if (map) { /* always */ }
if (map.size) { /* has entries */ }
Document all-in-one table
| Value | Boolean |
|---|---|
false |
false |
0, -0, 0n |
false |
'' |
false |
null, undefined |
false |
NaN |
false |
'false', '0' |
true |
[], {} |
true |
function(){} |
true |
Form and API data
// checkbox unchecked may be missing; input values are strings
if (formData.get('qty')) { /* '0' is truthy! */ }
if (Number(formData.get('qty'))) { /* 0 is falsy — maybe OK for qty */ }
Parse then validate with explicit rules, not raw truthiness.
Interview answer (out loud)
“Falsy values are false, 0, -0, 0n, empty string, null, undefined, and NaN. Everything else is truthy, including empty arrays and objects. I use ?? for nullish defaults so 0 and ‘’ survive, and I check .length/.size for empty collections.”
Double bang and Boolean in maps
const flags = values.map(Boolean);
const flags2 = values.map((v) => !!v);
Useful when normalizing API fields that arrive as 0|1 or messy types — still better to parse intentionally when 0 is data.
React rendering
{count && <Badge n={count} />}
// count=0 → renders 0 in React DOM — classic footgun
{count > 0 && <Badge n={count} />}
{!!count && <Badge n={count} />}
{count ? <Badge n={count} /> : null}
Truthy checks in JSX are not free of display side effects.
Document.all (archaeology)
Legacy document.all is falsy in a special weird way in browsers — don’t use it. Mention only if an interviewer goes deep on “are there other falsy objects?” Answer: not in modern portable JS; stick to the standard list.
Further reading
Related
Related guides
- AbortControllerCancel fetch and other async work with AbortController and AbortSignal — timeouts, race conditions, and cleanup when components unmount.
- Array find, some, every, includesShort-circuiting array predicates: find, findIndex, some, every, and includes — when to use each and common interview traps.
- Array map, filter, reducemap, filter, and reduce as the core transform toolkit — immutability, chaining costs, reduce patterns, and when a plain loop is clearer.
- Arrow Functions Deep DiveLexical this, no arguments object, no construct, concise bodies — when arrows help and when methods and generators need classic functions.
- Async Iteration and for await...ofAsync iterables, for await...of, and streaming data — how async iterators differ from Promise.all and when to use each.