Kodokon kodokon.com

tsconfig estricto: opciones clave y errores comunes

Entiendes lo que el modo estricto activa realmente y sabes gestionar los errores típicos que revela en un proyecto existente.

11 min · 3 preguntas

Abrir esta lección en Kodokon

"strict": true no es una opción sino un agregado que activa toda una familia de comprobaciones: strictNullChecks, noImplicitAny, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables y alwaysStrict. Cada nueva versión de TypeScript puede añadir más: activar strict te suscribe a las comprobaciones futuras. Cada flag se puede seguir desactivando individualmente, lo que permite una migración gradual en una base de código existente.

JSON
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true,
    "verbatimModuleSyntax": true,
    "skipLibCheck": true
  }
}
Una base estricta ampliada con opciones fuera del agregado (archivo JSON).

Los dos flags de mayor impacto son strictNullChecks y noImplicitAny. El primero elimina null y undefined de todos los tipos: cada valor potencialmente ausente debe declararse T | undefined y gestionarse antes de usarlo. El segundo se niega a dejar que un parámetro sin anotar recaiga en any. Juntos, eliminan las dos grandes familias de bugs de JavaScript: "cannot read property of undefined" y la propagación de valores sin verificar. useUnknownInCatchVariables completa el cuadro: la variable de un catch es unknown, porque JavaScript te deja lanzar cualquier cosa.

TYPESCRIPT
function findPort(
  env: Record<string, string | undefined>
): number {
  const raw = env["PORT"];
  if (raw === undefined) {
    return 3000;
  }
  return Number.parseInt(raw, 10);
}

declare function riskyOperation(): void;

try {
  riskyOperation();
} catch (err) {
  const message =
    err instanceof Error ? err.message : String(err);
  console.error(message);
}
Dos patrones estrictos: ausencia gestionada, catch como unknown.

Errores comunes de migración, y sus remedios reales. "Object is possibly undefined": prefiere la reducción (if), el encadenamiento opcional ?. o un valor por defecto con ?? en lugar de la aserción non-null !, que se limita a mover el fallo a otro lugar. "Property has no initializer" (strictPropertyInitialization): inicializa en el constructor en lugar de recurrir a ! sobre el campo. Vigila también la trampa ?? frente a ||: port || 3000 reemplaza también 0 y "", mientras que port ?? 3000 solo reemplaza null y undefined.

TYPESCRIPT
interface Settings { retries?: number }

function resolveRetries(s: Settings): number {
  const bad = s.retries || 3;
  const good = s.retries ?? 3;
  return good;
}

const names = ["Ada", "Linus"];
const first = names[0];
const upper = first?.toUpperCase() ?? "N/A";
retries: 0 da bad = 3 pero good = 0; el acceso indexado se comprueba a continuación.

Más allá del agregado, tres opciones merecen una discusión en equipo. noUncheckedIndexedAccess añade undefined a cada acceso indexado (arr[i], dict[key]): más seguro, pero verboso en código de manipulación de arrays; muchos equipos lo adoptan solo en proyectos nuevos. exactOptionalPropertyTypes distingue "propiedad ausente" de "propiedad establecida en undefined", crucial para los patches. skipLibCheck omite la comprobación de los archivos .d.ts de tus dependencias: un compromiso deliberado entre tiempo de build y detección de conflictos entre librerías.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. ¿Qué hace exactamente "strict": true en tsconfig.json?
    • Activa solo la opción strictNullChecks
    • Activa un conjunto de flags estrictos, cada uno de los cuales se puede seguir desactivando individualmente
    • Prohíbe cualquier uso del tipo any, incluso explícito
    • Fuerza la compilación en modo ES5
  2. Con retries?: number establecido en 0, ¿cuál es la diferencia entre retries || 3 y retries ?? 3?
    • Ninguna, ambos devuelven 0
    • || devuelve 3 porque 0 es falsy; ?? devuelve 0 porque solo reemplaza null y undefined
    • ?? devuelve 3 porque 0 se trata como ausente
  3. ¿Por qué preferir // @ts-expect-error en lugar de // @ts-ignore para marcar la deuda de tipado?
    • @ts-expect-error suprime varios errores a la vez
    • @ts-ignore no funciona en modo estricto
    • @ts-expect-error se convierte en error una vez resuelto el problema, así que la deuda se limpia sola