Optional chaining ?. y nullish coalescing ?? en TypeScript

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

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP