Una lista vacía no parece peligrosa hasta que el código ejecuta users[0].name. Un diccionario también parece completo hasta que una clave llega desde una petición, un archivo o una configuración que cambió. Sin una comprobación, TypeScript puede tratar ambas lecturas como si el valor estuviera garantizado.
noUncheckedIndexedAccess cambia ese contrato. Cuando está activada, una lectura por índice que puede no encontrar un valor incluye undefined. El compilador no elige la solución. Obliga al código a elegir una guarda, un fallback, otra forma de iteración, Map o una invariante que realmente puedas demostrar.
Este artículo muestra el comportamiento con arrays y objetos cuyas claves son cadenas, una fixture mínima comprobada con TypeScript 5.9.3 y una migración gradual. La opción mejora la seguridad estática del código. No valida el JSON recibido por la red.

Respuesta breve
- Activa
noUncheckedIndexedAccessjunto constrictcuando las lecturas por índice deban expresar que falta un valor.- Trata
array[i]yrecord[key]como valores que pueden serundefined.- Prefiere
for...of, una guarda explícita o un fallback propio del dominio.- Usa
!solo cuando existe una invariante establecida fuera de esa línea y todavía se puede comprobar.
¿Qué cambia con noUncheckedIndexedAccess?
La referencia de TypeScript sobre noUncheckedIndexedAccess explica que la opción añade undefined a una propiedad no declarada cubierta por una index signature. La misma idea se aplica a una posición de un array que puede quedar fuera de sus límites. El tipo representa ahora una ausencia que ya era posible en runtime.
Sin la opción, este código compila aunque users esté vacío:
interface User {
id: string;
name: string;
}
const users: User[] = [];
const first = users[0];
console.log(first.name);
Con noUncheckedIndexedAccess: true, first es User | undefined. La línea que lee name debe decidir qué significa una lista vacía:
const first = users[0];
if (first) {
console.log(first.name);
} else {
console.log("no se encontró ningún usuario");
}
La ventaja no es que el array se vuelva más seguro en runtime. Todavía puede estar vacío. La ventaja es que el tipo deja de ocultar la suposición, así que el código toma la decisión donde sabe si la ausencia es normal, un error o un motivo para volver a intentarlo.
¿Por qué strict no activa esta opción?
Las notas de TypeScript 4.1 explican que noUncheckedIndexedAccess puede generar ruido en muchos archivos, por lo que no forma parte del grupo que activa strict. Un proyecto puede usar strict: true y seguir tratando items[index] como si siempre devolviera un elemento.
Ese detalle cambia cómo debes leer tsconfig.json. strict es un buen punto de partida, pero no promete que todas las lecturas por índice hayan sido comprobadas. Para activar esta comprobación, añádela explícitamente:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true
}
}
La opción no convierte todos los tipos en T | undefined. Las propiedades declaradas siguen siendo conocidas. El efecto aparece cuando la clave o la posición no están garantizadas por el tipo, como un índice numérico de un array o una clave string usada contra Record<string, T>.
¿Dónde aparecen primero los errores?
La FAQ de TypeScript describe esta configuración como una comprobación amplia. No intenta demostrar que cada acceso está dentro de los límites. Por eso la primera compilación suele señalar patrones que parecían inofensivos, pero dependían de que los datos estuvieran presentes.
| Lectura | Tipo con la opción | Solución que suele comunicar mejor la intención |
|---|---|---|
users[0] |
User | undefined |
comprobar la ausencia o usar una API con un resultado opcional explícito |
users[index] |
User | undefined |
guardar el elemento y estrechar ese valor |
usersById[id] |
User | undefined |
tratar la clave desconocida o usar Map.get con el mismo contrato |
path.split("/")[3] |
string | undefined |
validar la estructura antes de usar la parte |
map.get(id) |
ya puede ser User | undefined |
seguir tratando la ausencia |
Un error común es esperar que una comprobación de límites resuelva todo:
for (let index = 0; index < users.length; index += 1) {
users[index].name;
}
Las notas de TypeScript registran que incluso un bucle con index < length puede seguir produciendo un error. El compilador no convierte esa condición en una prueba permanente sobre una estructura que podría cambiar. Si necesitas el índice, lee el elemento, comprueba el resultado y solo después accede a sus propiedades.
¿Cómo corregir los errores sin usar ! para silenciar el compilador?
Elige la solución según el significado de la ausencia. Cuando hay que procesar cada elemento presente, for...of elimina el índice y expresa esa intención directamente:
for (const user of users) {
console.log(user.name);
}
Cuando la ausencia es posible y cambia el resultado, usa una guarda:
const user = usersById[userId];
if (!user) {
return { ok: false, reason: "user-not-found" };
}
return { ok: true, user };
Un fallback también puede ser correcto, pero debe pertenecer al dominio. const limit = settings[key] ?? defaultLimit comunica una regla. settings[key]! solo afirma que la regla existe sin registrarla en el código. Si alguien cambia la clave, mueve la inicialización o modifica el origen de los datos, la aserción no encontrará el problema.
Para diccionarios con muchas lecturas y claves externas, considera si Map representa mejor la operación. Map.get ya devuelve T | undefined, así que la decisión sobre la ausencia es visible incluso sin esta opción. Eso no hace que Map sea siempre mejor. Significa que el tipo encaja con una colección donde la clave puede no existir.
Una buena migración no convierte cada error en if (!value) return. Clasifica cada lectura como ausencia normal, configuración inválida, valor que necesita un fallback o invariante establecida por otro paso. El tipo solo es honesto cuando el comportamiento elegido también lo es.
¿Cómo activar la opción sin detener todo el proyecto?
Trata el cambio como un contrato del compilador. Antes de corregir líneas, ejecuta el typecheck actual y anota el comando que usa CI. Después haz el cambio en una configuración o un paquete con un límite claro.
Una secuencia pequeña ayuda:
- Activa
noUncheckedIndexedAccessen eltsconfigdel paquete elegido. - Ejecuta
npx tsc --noEmitcon el mismo proyecto que usa CI. - Agrupa los errores en arrays, records, cadenas divididas y tipos de librerías.
- Corrige cada grupo con una guarda, una iteración, un fallback o una estructura de datos adecuada.
- Ejecuta pruebas que cubran listas vacías, claves desconocidas y configuraciones incompletas.
- Mantén la opción activa en CI para que las nuevas lecturas por índice no recuperen la suposición.
Para esta página comprobé una fixture mínima con strict, noUncheckedIndexedAccess y noEmit usando TypeScript 5.9.3. Compila después de estrechar los valores leídos y demuestra el comportamiento descrito en la documentación. No es un benchmark de migración. Una base real puede tener errores en tipos de dependencias, archivos generados, pruebas y código que mezcla JavaScript con TypeScript.
Si el paquete pertenece a un monorepo, introduce la opción en el límite de un proyecto y después pásala a sus dependientes. El artículo sobre Project References de TypeScript explica cómo separar proyectos y mantener explícito el orden del build. La preocupación aquí es distinta: el grafo de build organiza la compilación, mientras esta opción cambia los tipos de las lecturas dentro de él.
Cuando la lectura forma parte del resultado de una petición, tipar respuestas de éxito y error de fetch en TypeScript ayuda a separar un fallo de transporte de una ausencia dentro del dato.
¿Qué no comprueba la opción?
noUncheckedIndexedAccess actúa durante la comprobación del código que escribiste. No inspecciona el JSON de la red, no confirma que una clave externa tenga la forma esperada ni impide que otra capa pase un valor incorrecto mediante any. Una interfaz de TypeScript tampoco valida datos en runtime.
Cuando un valor cruza una frontera externa, léelo como unknown y valida su forma antes de usarlo. La guía sobre validar JSON externo antes de usarlo en TypeScript cubre ese paso. Las dos protecciones son útiles: la validación en runtime prueba el valor recibido, mientras noUncheckedIndexedAccess mantiene honestas las lecturas posteriores.
La opción tampoco detecta todos los problemas de objetos dinámicos. Una clave como __proto__, una colisión con una propiedad heredada o un contrato de autorización necesitan una decisión en runtime. Combina tipos con validación, estructuras de datos y pruebas que alcancen la frontera real.
Usa pruebas unitarias o de integración en Node.js para decidir si la corrección debe demostrar solo la lógica de estrechamiento o también la fuente que produce las claves y posiciones.
Preguntas frecuentes
¿noUncheckedIndexedAccess forma parte de strict?
No. Las notas de TypeScript 4.1 explican que la opción no se activa con strict porque puede crear mucho trabajo de migración. Añade "noUncheckedIndexedAccess": true por separado cuando quieras que arrays e index signatures expresen que un valor puede ser undefined.
¿Por qué for...of suele corregir el error del array?
for...of entrega cada elemento existente en la iteración, en lugar de pedir al compilador que demuestre el resultado de un índice numérico. No vuelve confiable una fuente externa ni impide cambios fuera del bucle. Elige una operación cuyo contrato coincide mejor con procesar cada elemento presente.
¿Puedo usar ! después de activar la opción?
Sí, pero el operador debe representar una invariante que el programa haya establecido realmente. Si una función solo puede ejecutarse después de cargar una configuración obligatoria, documenta y prueba esa precondición. Para una clave, posición o respuesta que normalmente puede faltar, ! elimina la evidencia sin corregir el comportamiento.
¿La opción sustituye la validación de JSON?
No. Comprueba tipos y lecturas en el código compilado. JSON, variables de entorno y respuestas HTTP llegan en runtime y necesitan su propia validación. Trata la entrada como unknown, valida su forma y conserva el código TypeScript protegido contra índices ausentes dentro del flujo.
Conclusión
Activar noUncheckedIndexedAccess hace explícita una pregunta: ¿el valor está realmente ahí? La respuesta puede ser una guarda, un fallback, for...of, Map.get o una invariante verificable. El compilador no impone una política, pero deja de aceptar el silencio como prueba.
Empieza con un paquete pequeño, ejecuta el mismo typecheck que CI y corrige los errores según el significado de la ausencia. No uses ! para convertir una duda de datos en certeza de tipos. Mantén clara la frontera: esta opción mejora el código que compilas, mientras los valores externos siguen necesitando validación en runtime.
Fuentes consultadas
- TypeScript, "TSConfig: noUncheckedIndexedAccess", consultado el 2026-10-05.
- TypeScript, "TypeScript 4.1 release notes", consultado el 2026-10-05.
- TypeScript Wiki, "FAQ: Assume Array Access Might Be Out of Bounds", consultado el 2026-10-05.
- DEV Community, "TypeScript's noUncheckedIndexedAccess: Turn It On, See What Breaks", consultado el 2026-10-05. Usado como señal de lenguaje y migración, no como prueba del comportamiento del compilador.
La asistencia de IA ayudó a organizar la investigación, redactar la prosa, localizar las versiones y crear la ilustración. La fixture y las afirmaciones técnicas se comprobaron con la documentación citada; la imagen es explicativa y no representa una salida del compilador.