跪拜 Guibai
← All articles
Frontend

The `||` vs `??` Trap That Broke 30% of User Avatars

By Csvn ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

This bug is a rite of passage for every JavaScript developer, but it's also a production-level reminder that subtle operator semantics can silently corrupt data display at scale. For teams building UIs that handle user-generated content, scores, or status flags, the `||` vs `??` distinction isn't academic — it's a reliability issue that directly impacts user trust.

Summary

A production incident last Friday saw 30% of user avatars go blank, despite the avatar API returning valid data. The root cause was a seemingly innocuous line of code: `const avatarUrl = user.avatar?.url || '/default-avatar.png'`. The `||` operator treats all falsy values — including empty strings — as 'not present', so when the avatar service returned `url: ""` for users whose image processing had failed, the default avatar was shown instead.

The fix was straightforward: switch to the nullish coalescing operator `??`, which only falls back on `null` or `undefined`, preserving empty strings, `0`, and `false`. The team also added an ESLint rule (`@typescript-eslint/prefer-nullish-coalescing`) and a code review checklist item to catch future misuse.

Beyond avatars, the same pattern causes bugs with scores of `0` showing as 'No data', CSS classes being overwritten by empty strings, and confusion around function default parameters (which behave like `??`, not `||`). The golden rule: use `??` when you mean 'no data', and only use `||` when you explicitly want to filter falsy values like empty user input.

Takeaways
30% of user avatars showed the default image because `||` treated empty strings as falsy and fell back to the default.
The avatar service returned `url: ""` when image processing failed, which is semantically different from 'no avatar'.
Switching to `??` (nullish coalescing) fixed the bug because it only falls back on `null` or `undefined`.
The team added an ESLint rule `@typescript-eslint/prefer-nullish-coalescing` to prevent future misuse.
Function default parameters behave like `??`, not `||` — they only trigger on `undefined`.
A code review checklist rule was added: 'Whenever you see `||` with a variable, first think: should this be `??`?'
Conclusions

The bug reveals a common semantic mismatch: backend APIs often use empty strings to signal 'exists but broken', while frontend logic treats empty strings as 'absent'.

The `||` operator is a legacy from early JavaScript when `??` didn't exist; many codebases still default to `||` out of habit, not intent.

Adding an ESLint rule is a good start, but the real fix is cultural — teaching developers to think about what 'no data' means in their specific domain.

The incident highlights how a single line of code can cause a 30% data corruption bug, underscoring the value of defensive programming and explicit null handling.

Function default parameters being `undefined`-only is a common point of confusion; the article's warning is well-placed.

Concepts & terms
Nullish Coalescing Operator (`??`)
A JavaScript operator that returns the right-hand value only when the left-hand value is `null` or `undefined`. It preserves other falsy values like `0`, `''`, and `false`, making it safer for default values in data display.
Falsy Values
Values in JavaScript that evaluate to `false` in a boolean context: `false`, `0`, `''` (empty string), `null`, `undefined`, and `NaN`. The `||` operator treats all of these as 'not present'.
Optional Chaining (`?.`)
A JavaScript operator that allows safe access to nested object properties without throwing an error if an intermediate property is `null` or `undefined`. Returns `undefined` if the chain breaks.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗