TypeScript de Cero a Experto / Configuración pro
Chequeos extra: la segunda capa de rigor
strict cubre lo esencial, pero TypeScript guarda una segunda capa de comprobaciones
que NO vienen en strict y que valen oro: la que atrapa accesos a arrays inseguros,
variables muertas y returns olvidados. Activarlas es lo que separa un proyecto bueno de
uno impecable —el nivel de configuración de los equipos que se toman la calidad en
serio.
Las alarmas opcionales que sí vale la pena poner
noUncheckedIndexedAccess: el hueco de los arrays
El chequeo más importante que NO está en strict. Sin él, array[i] se tipa como T
—mintiendo, porque el índice podría no existir:
const gastos: number[] = [100, 200, 300];
// SIN noUncheckedIndexedAccess (default): TS miente diciendo que es number
const x = gastos[10]; // tipo: number (¡pero en runtime es undefined!)
x.toFixed(2); // ✅ para TS... 💥 undefined.toFixed en runtime
// CON noUncheckedIndexedAccess: TS es honesto, el acceso es T | undefined
const y = gastos[10]; // tipo: number | undefined
y.toFixed(2); // ❌ 'y' is possibly 'undefined' — TS te frena
if (y !== undefined) y.toFixed(2); // ✓ te obliga a chequearstrictNullChecks cubre los null de variables, pero deja este agujero: acceder a un
índice que no existe da undefined en runtime, y sin noUncheckedIndexedAccess, TS lo
tipa como si siempre existiera. Activarlo cierra el hueco —a cambio de que manejes el
undefined en accesos por índice. Molesta un poco, previene mucho; muchos equipos serios
lo consideran casi obligatorio.
Código muerto: noUnusedLocals y noUnusedParameters
Estos cazan variables y parámetros que declaras pero nunca usas —basura que se acumula y confunde:
function calcular(a: number, b: number, c: number): number {
const temporal = a * 2; // ❌ noUnusedLocals: 'temporal' is declared but never used.
return a + b; // ❌ noUnusedParameters: 'c' is declared but never used.
}
// te obligan a limpiar: borrar lo que no usas, o marcar params intencionalmente
// sin usar con un guion bajo (convención que estos flags respetan):
function manejar(_evento: Event, datos: string): void {
console.log(datos); // _evento no se usa, y el _ lo declara intencional
}noUnusedLocals y noUnusedParameters mantienen tu código limpio: nada de variables
olvidadas ni parámetros fantasma. El truco del guion bajo (_evento) le dice "sé que no
lo uso, es a propósito" —útil cuando la firma exige un parámetro que no necesitas.
Blindar el flujo: switch y returns
Dos chequeos que atrapan errores de lógica clásicos:
// noImplicitReturns: TODAS las rutas deben devolver (o ninguna):
function clasificar(n: number): string {
if (n > 0) return "positivo";
if (n < 0) return "negativo";
// ❌ noImplicitReturns: Not all code paths return a value. (falta el caso n === 0)
}
// noFallthroughCasesInSwitch: un case sin 'break'/'return' que "cae" al siguiente es error:
function color(estado: string): string {
switch (estado) {
case "activo":
console.log("activo");
// ❌ noFallthroughCasesInSwitch: falta break/return, cae en "inactivo"
case "inactivo":
return "gris";
default:
return "negro";
}
}Con strict activo, escribes const primero = miArray[0] y usas primero.nombre sin chequear, y en producción a veces sale undefined. ¿Qué flag lo habría cazado?
Mini-reto
Sube el rigor: 1) en un tsconfig, agrega noUncheckedIndexedAccess: true y observa
cómo un array[0] ahora es T | undefined; 2) deja una variable local sin usar con
noUnusedLocals activo y mira el error; 3) escribe una función con un if que no cubre
todos los casos con noImplicitReturns y observa la queja. Siente cómo cada flag te
empuja a un código más honesto.
Qué sigue
Tu compilador ya es riguroso. Ahora hagámoslo cómodo: los paths de TypeScript te
dejan escribir @/componentes/Boton en vez de ../../../componentes/Boton —adiós a los
imports con laberintos de puntos. La próxima lección configura la resolución de módulos
para que tu código se lea limpio.