Usa ?? para valores por defecto, no ||
Este bug de valores por defecto en JavaScript probablemente está en tu código ahora mismo. config.port || 3000 parece perfectamente razonable — y en silencio convierte un puerto 0 en 3000, un prefijo vacío en tu string de respaldo, y un false explícito en true. La solución son dos caracteres: ??.
El bug: || evalúa veracidad, no presencia
x || y devuelve y siempre que x sea falsy. JavaScript tiene seis valores falsy: false, 0, "" (cadena vacía), null, undefined y NaN. Cuatro de ellos son valores de configuración perfectamente válidos:
const port = config.port || 3000; // 0 -> 3000 (bug)
const prefix = config.prefix || "app"; // "" -> "app" (bug)
const retries = config.retries || 5; // 0 -> 5 (bug)
const debug = config.debug || true; // false -> true (¡bug!)
El usuario definió esos valores. || los descarta porque no distingue "ausente" de "falsy". port: 0 es una petición real — "dame un puerto libre aleatorio" en server.listen(0) de Node — y debug: false es la forma más común de apagar algo.
La solución: ?? evalúa nullish, no falsy
El operador nullish coalescing (??, ES2020) aplica el fallback solo cuando el lado izquierdo es null o undefined:
const port = config.port ?? 3000; // 0 stays 0
const prefix = config.prefix ?? "app"; // "" stays ""
const retries = config.retries ?? 5; // 0 stays 0
const debug = config.debug ?? true; // false stays false
¿La clave no existe? config.port es undefined y obtienes 3000. ¿null explícito? Obtienes 3000. Cualquier otra cosa — incluidos todos los valores falsy que el usuario quiso poner — sobrevive.
Reglas prácticas
| Valor de entrada | x || 3000 | x ?? 3000 |
|---|---|---|
undefined | 3000 | 3000 |
null | 3000 | 3000 |
0 | 3000 | 0 |
"" | fallback | "" |
false | fallback | false |
NaN | fallback | NaN |
8080 | 8080 | 8080 |
Conserva || solo cuando de verdad quieras tratar todos los valores falsy como ausentes — p. ej. normalizar texto del usuario donde "" debe volverse un placeholder. Para configuración, objetos de opciones y respuestas de API, usa ??.
Rincón para usuarios avanzados
??=para objetos de opciones (ES2021).options.timeout ??= 100asigna solo cuando la propiedad esnull/undefined— reemplaza en una línea el clásicoif (options.timeout == null), y hace cortocircuito (el lado derecho ni siquiera se evalúa si no aplica).- Combínalo con optional chaining.
customer?.address?.city ?? "Unknown"nunca lanza error con una rama ausente y solo aplica el default ante una ausencia real — el idioma estándar de lectura profunda con default. - Ambos hacen cortocircuito.
a ?? expensiveDefault()nunca llama a la función cuandoaestá presente — seguro para fallbacks costosos o perezosos. - Usa paréntesis al mezclar.
a || b ?? ces unSyntaxErrorpor diseño de la especificación; escribe(a || b) ?? c. La ambigüedad se consideró tan peligrosa que se prohibió directamente. - Audita los que ya publicaste. Busca con grep
|| 0,|| '',|| falsey|| <número>en lecturas de config/opciones — cada uno es candidato exacto a este bug.
Recursos
- Operador nullish coalescing (
??) — MDN - OR lógico (
||) — MDN - Asignación nullish coalescing (
??=) — MDN - Optional chaining (
?.) — MDN - Propuesta TC39: nullish coalescing
¿Construyendo una funcionalidad con IA? Yeda AI diseña, audita y entrega sistemas LLM de producción.