El optional chaining (?.) y el nullish coalescing (??) son dos operadores de JavaScript que TypeScript entiende y aprovecha para narrowing. Simplifican el acceso a propiedades anidadas que pueden ser null o undefined, y asignan valores por defecto de forma precisa, sin el problema de los falsy values que tiene el operador ||.
Optional chaining: acceso seguro a propiedades anidadas
?. cortocircuita y devuelve undefined si el valor a la izquierda es null o undefined, en lugar de lanzar un TypeError:
interface Usuario {
id: number;
perfil?: {
nombre?: string;
avatar?: {
url: string;
ancho: number;
};
};
}
const usuario: Usuario = { id: 1 };
// Sin optional chaining (verboso y propenso a errores):
const url = usuario.perfil && usuario.perfil.avatar && usuario.perfil.avatar.url;
// Con optional chaining:
const urlAvatar = usuario.perfil?.avatar?.url;
// string | undefined
Optional chaining con funciones y arrays
?. funciona también para llamadas a funciones opcionales y acceso a elementos de arrays:
interface Elemento {
onClick?: (evento: Event) => void;
hijos?: string[];
}
function manejar(el: Elemento, ev: Event): void {
el.onClick?.(ev); // Solo llama si onClick existe
const primero = el.hijos?.[0]; // string | undefined
}
Nullish coalescing: valor por defecto preciso
?? devuelve el operando derecho solo cuando el izquierdo es null o undefined. A diferencia de ||, no activa el fallback para otros valores falsy como 0, "" o false:
const timeout = opciones.timeout ?? 5000; // 5000 solo si timeout es null o undefined // Si timeout es 0, usa 0 (no el fallback) // El problema con ||: const timeoutMal = opciones.timeout || 5000; // 5000 si timeout es 0, "" o false ? BUG potencial
function formatearNombre(nombre: string | null | undefined): string {
return nombre ?? "Anónimo";
}
formatearNombre("Ana"); // "Ana"
formatearNombre(null); // "Anónimo"
formatearNombre(undefined); // "Anónimo"
formatearNombre(""); // "" (cadena vacía: no es null ni undefined)
El operador ??= : asignación condicional
??= asigna el valor de la derecha a la variable solo si esta es null o undefined. Es equivalente a x = x ?? valor:
interface Cache {
[clave: string]: string | undefined;
}
const cache: Cache = {};
function obtenerOCachear(clave: string, calcular: () => string): string {
cache[clave] ??= calcular(); // Solo ejecuta calcular() si no hay valor
return cache[clave]!;
}
Uso con TypeScript y strictNullChecks
Con strictNullChecks: true, TypeScript distingue entre T, T | null y T | undefined. El optional chaining y el nullish coalescing se integran con el sistema de tipos de forma natural:
interface Configuracion {
db?: {
host: string;
puerto?: number;
};
}
function obtenerPuerto(config: Configuracion): number {
return config.db?.puerto ?? 5432;
// TypeScript infiere number (no number | undefined)
// porque ?? garantiza un fallback cuando puerto es undefined
}
La regla práctica: usa ?. para acceder a propiedades que pueden no existir en lugar de encadenar comprobaciones con &&. Usa ?? para valores por defecto cuando el falsy value 0, "" o false es un valor válido que no debe activar el fallback. Si cualquier falsy value debe activarlo, || sigue siendo la opción correcta.
Imagen: Pexels / Pixabay
