CAP 08 · LEC 05·Arrays y objetos avanzados

Optional chaining y nullish coalescing: acceso seguro

El operador ?. accede a propiedades sin explotar si el valor es null o undefined. El operador ?? asigna un valor por defecto solo cuando el valor es null o undefined — no para 0, '' o false.

● PRINCIPIANTE6 min lectura4 ejerciciospor Fernando Herrera · actualizado mayo de 2026
¿Encontraste un error o algo que mejorar?Editá esta lección en GitHub →

Optional chaining ?. — accede sin explotar

Cuando accedes a objeto.propiedad.subPropiedad y propiedad es null o undefined, JavaScript lanza un TypeError. El operador ?. cortocircuita y devuelve undefined en lugar de lanzar.

const usuario = { nombre: "Ana", direccion: { ciudad: "Madrid", codigoPostal: "28001", }, }; const usuarioSinDireccion = { nombre: "Carlos" }; // Sin ?. — TypeError si 'direccion' no existe // console.log(usuarioSinDireccion.direccion.ciudad); // 💥 Error // Con ?. — devuelve undefined sin explotar console.log(usuario.direccion?.ciudad); // "Madrid" console.log(usuarioSinDireccion.direccion?.ciudad); // undefined // Cadenas de ?. — se detiene en el primer null/undefined const config = null; console.log(config?.servidor?.host?.puerto); // undefined (no explota) // Resultado con fallback usando || const ciudad = usuarioSinDireccion.direccion?.ciudad || "Ciudad desconocida"; console.log(ciudad); // "Ciudad desconocida"
interface Direccion { ciudad: string; codigoPostal: string; } interface Usuario { nombre: string; direccion?: Direccion; // propiedad opcional } const usuario: Usuario = { nombre: "Ana", direccion: { ciudad: "Madrid", codigoPostal: "28001" }, }; const sinDireccion: Usuario = { nombre: "Carlos" }; // TypeScript sabe que direccion puede ser undefined // Sin ?., te advertiría de un posible error const ciudad1 = usuario.direccion?.ciudad; // string | undefined const ciudad2 = sinDireccion.direccion?.ciudad; // undefined console.log(ciudad1); // "Madrid" console.log(ciudad2); // undefined
SalidaMadrid undefined undefined Ciudad desconocida

?. con métodos — objeto?.metodo()

También funciona con llamadas a métodos. Si el objeto es null o undefined, no se llama al método y el resultado es undefined.

const procesador = { transformar: (texto) => texto.toUpperCase(), }; const procesadorInactivo = null; // Llama el método solo si el objeto existe console.log(procesador?.transformar("hola")); // "HOLA" console.log(procesadorInactivo?.transformar("hola")); // undefined — sin error // Muy útil con callbacks opcionales function ejecutarTarea(tarea, alCompletar) { const resultado = tarea(); alCompletar?.(resultado); // Solo llama si alCompletar existe return resultado; } const res = ejecutarTarea( () => 42, (r) => console.log("Completado:", r) ); // "Completado: 42" const resSilencioso = ejecutarTarea(() => 99); // Sin output — alCompletar era undefined
interface Formateador { formatear: (valor: number) => string; } function mostrarPrecio( precio: number, formateador?: Formateador ): string { // Si formateador es undefined, ?.formatear() devuelve undefined return formateador?.formatear(precio) ?? `$${precio}`; } const euroFormateador: Formateador = { formatear: (n) => `${n.toFixed(2)}`, }; console.log(mostrarPrecio(29.99, euroFormateador)); // "€29.99" console.log(mostrarPrecio(29.99)); // "$29.99"
SalidaHOLA undefined Completado: 42

?. con arrays — array?.[0]

Para acceder a índices de arrays de forma segura, usa la sintaxis array?.[indice]. Los corchetes son necesarios porque array?.0 no es sintaxis válida.

const respuesta = { datos: { usuarios: ["Ana", "Carlos", "Bea"], }, }; const respuestaVacia = { datos: null }; // Acceso seguro al primer elemento console.log(respuesta.datos?.usuarios?.[0]); // "Ana" console.log(respuestaVacia.datos?.usuarios?.[0]); // undefined // Caso real: respuesta de API que puede venir vacía function obtenerPrimerResultado(respuestaAPI) { return respuestaAPI?.resultados?.[0]?.titulo ?? "Sin resultados"; } console.log(obtenerPrimerResultado({ resultados: [{ titulo: "JavaScript avanzado" }], })); // "JavaScript avanzado" console.log(obtenerPrimerResultado({ resultados: [] })); // "Sin resultados" console.log(obtenerPrimerResultado(null)); // "Sin resultados"
interface Resultado { titulo: string; url: string; } interface RespuestaAPI { resultados?: Resultado[]; total?: number; } function obtenerPrimerResultado(resp: RespuestaAPI | null): string { return resp?.resultados?.[0]?.titulo ?? "Sin resultados"; } const conResultados: RespuestaAPI = { resultados: [{ titulo: "TypeScript avanzado", url: "/ts" }], }; console.log(obtenerPrimerResultado(conResultados)); // "TypeScript avanzado" console.log(obtenerPrimerResultado({ resultados: [] })); // "Sin resultados" console.log(obtenerPrimerResultado(null)); // "Sin resultados"
SalidaAna undefined JavaScript avanzado Sin resultados Sin resultados

Nullish coalescing ?? — valor por defecto preciso

El operador || da el valor derecho si el izquierdo es falsy (incluye 0, "", false). El operador ?? es más preciso: solo activa el valor derecho si el izquierdo es null o undefined.

Valorcon ||con ??¿Cuál es correcto?
undefinedusa el defaultusa el defaultAmbos iguales
nullusa el defaultusa el defaultAmbos iguales
0usa el default ❌usa el 0 ✅?? es correcto
""usa el default ❌usa "" ✅?? es correcto
falseusa el default ❌usa false ✅?? es correcto
// Configuración de un gráfico const config = { mostrarEjes: false, // false es un valor válido opacidad: 0, // 0 es un valor válido titulo: "", // string vacío puede ser intencional }; // ❌ Con || — trata 0, false y "" como "sin valor" const ejesConOR = config.mostrarEjes || true; // true — ¡incorrecto! const opacidadOR = config.opacidad || 1; // 1 — ¡incorrecto! const tituloOR = config.titulo || "Sin título"; // "Sin título" — ¡incorrecto! // ✅ Con ?? — solo actúa sobre null y undefined const ejesConQQ = config.mostrarEjes ?? true; // false — correcto ✅ const opacidadQQ = config.opacidad ?? 1; // 0 — correcto ✅ const tituloQQ = config.titulo ?? "Sin título"; // "" — correcto ✅ console.log("||:", ejesConOR, opacidadOR, tituloOR); // true 1 "Sin título" console.log("??:", ejesConQQ, opacidadQQ, tituloQQ); // false 0 ""
interface ConfigGrafico { mostrarEjes?: boolean; opacidad?: number; titulo?: string; } function normalizarConfig(config: ConfigGrafico): Required<ConfigGrafico> { return { // ?? garantiza que 0, false y "" se respetan mostrarEjes: config.mostrarEjes ?? true, opacidad: config.opacidad ?? 1, titulo: config.titulo ?? "Sin título", }; } console.log(normalizarConfig({ mostrarEjes: false, opacidad: 0, titulo: "" })); // { mostrarEjes: false, opacidad: 0, titulo: "" } console.log(normalizarConfig({})); // { mostrarEjes: true, opacidad: 1, titulo: "Sin título" }
Salida||: true 1 Sin título ??: false 0

Practica