unit U2 — 2 of 5
Falsy values & coercion
?? vs ||, string numbers, string booleans
The most expensive bugs in data shaping are not missing fields — those are loud. They are values that exist, pass a truthiness check, and mean something different from what you assumed. `0` is a real deal size and a falsy value. An empty string is a present-but-useless company name. The string `"false"` is truthy. `null` means "known to be absent" while `undefined` means "never provided", and one API will send you both for the same concept.
The tools are precise, so use them precisely. `??` falls back only on `null` and `undefined`; `||` also fires on `0`, `""` and `false`, which is why a `dealSize || 100` default silently rewrites every genuinely zero-value deal. `?.` stops a lookup safely at a missing link rather than throwing. When a number arrives as a string — which it does, constantly, from form encodings and spreadsheets — convert it explicitly and check the result, because `Number("")` is `0` and `Number("12 units")` is `NaN`, and both will happily flow downstream.
Where it breaks: a default that hides a real value. `score || 50` looks like a sensible fallback and quietly replaces every legitimate score of zero with fifty. Reach for `??` unless you specifically mean "also replace empty and zero", and when you do mean that, say so in a comment so the next person does not "fix" it.
worked example
The same three fields handled carelessly and carefully — the difference is invisible until a zero arrives.
// careless — each line has a case where it silently lies const size = input.dealSize || 100; // a real 0 becomes 100 const name = input.company || 'Unknown'; // "" becomes Unknown, fine — but so does a real "" const active = Boolean(input.isActive); // the STRING "false" is true // careful const size = input.dealSize ?? 100; // only null/undefined fall back const name = input.company?.trim() || 'Unknown'; // "" IS meaningless here, so || is right const active = input.isActive === true || input.isActive === 'true'; // numbers arriving as strings, checked rather than trusted const raw = Number(input.amount); const amount = Number.isFinite(raw) ? raw : null; // "" -> 0, "12 units" -> NaN
field checklist
- Use ?? for fallbacks; reach for || only when 0 and "" really are invalid.
- Treat null (known absent) and undefined (never sent) as different signals.
- Convert strings to numbers explicitly and check with Number.isFinite.
- Never trust a string boolean — compare it, do not cast it.
- Comment any deliberate use of || so nobody "fixes" it later.
common failure — Every zero-value deal became one hundred
A scoring step used `dealSize || 100` as a default for missing values. Free-trial signups legitimately have a deal size of zero, and every one of them was rewritten to one hundred — so the client’s pipeline forecast counted trials as real revenue for two quarters. `??` falls back only on null and undefined; `||` also fires on 0, "" and false. Choose deliberately and say which you meant.
check your understanding
A step uses `dealSize || 100` to default a missing value. Free-trial leads legitimately have `dealSize: 0`. What happens to them?
next unit opens once this is passed
sandbox validation
The check above confirms you followed the unit. Marking the module COMPLETED takes more: build the automation in your own engine and submit the exported flow and its run evidence, signed, to your unique validation URL. See the module page for that spec.