Modo Estricto de TypeScript y Verificaciones del Compilador
Habilita las opciones estrictas del compilador de TypeScript para detectar más errores en tiempo de compilación y complementar ESLint con seguridad de tipos.
Receta
Tarjeta de referencia rápida — lista para copiar y pegar.
# Verifica tipos sin emitir archivos
npx tsc --noEmit
# Verifica tipos en modo watch durante desarrollo
npx tsc --noEmit --watch
# Agregue a package.json
# "type-check": "tsc --noEmit"Cuándo usarlo: Todo proyecto TypeScript debe habilitar strict mode. La pregunta no es si, sino qué tan rápido puedes activar cada opción.
Ejemplo de Trabajo
// tsconfig.json
{
"compilerOptions": {
// --- Strict mode (flag sombrilla) ---
"strict": true,
// "strict" habilita todas estas:
// "strictNullChecks": true,
// "strictFunctionTypes": true,
// "strictBindCallApply": true,
// "strictPropertyInitialization": true,
// "noImplicitAny": true,
// "noImplicitThis": true,
// "alwaysStrict": true,
// "useUnknownInCatchVariables": true,
// --- Verificaciones estrictas adicionales (no en "strict") ---
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
// --- Configuración de módulos e imports ---
"verbatimModuleSyntax": true,
"moduleResolution": "bundler",
"module": "esnext",
"target": "es2017",
// --- Alias de rutas ---
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
// --- Salida ---
"noEmit": true,
"jsx": "preserve",
"incremental": true,
// --- Interoperabilidad ---
"esModuleInterop": true,
"allowJs": true,
"resolveJsonModule": true,
"isolatedModules": true,
"skipLibCheck": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}Lo que esto demuestra:
- Modo
strictcompleto habilitado como línea base - Verificaciones adicionales más allá de
strictpara máxima seguridad verbatimModuleSyntaxpara imports de solo tipo explícitosnoUncheckedIndexedAccesspara forzar verificaciones nulas en acceso a arrays y objetos- Configuración compatible con Next.js (
noEmit,jsx: "preserve",moduleResolution: "bundler")
Análisis Profundo
Cómo Funciona
"strict": truees una flag sombrilla que habilita ocho verificaciones estrictas individuales- Flags adicionales como
noUncheckedIndexedAccessno están incluidas enstricty deben habilitarse por separado - TypeScript verifica en tiempo de compilación y detecta una clase completa de errores que ESLint no puede (desajustes de tipo, propiedades faltantes, firmas de función incorrectas)
tsc --noEmitejecuta el verificador de tipos sin producir archivos de salida (Next.js maneja la compilación vía SWC)
Variaciones
Lo que cada opción estricta detecta:
| Opción | Qué Detecta |
|---|---|
strictNullChecks | Acceso a valores potencialmente null o undefined sin verificación |
noImplicitAny | Variables o parámetros sin tipo que asumen el tipo any |
strictFunctionTypes | Asignaciones de tipo de parámetro de función inseguras |
noUncheckedIndexedAccess | Acceso a array[i] u obj[key] sin verificación nula |
noImplicitReturns | Funciones que no retornan un valor en todas las rutas de código |
noFallthroughCasesInSwitch | Falta de break o return en casos switch |
noImplicitOverride | Anulación de métodos de clase base sin palabra clave override |
exactOptionalPropertyTypes | Asignación explícita de undefined a propiedades opcionales |
verbatimModuleSyntax | Fuerza import type para imports de solo tipo |
Habilitación del modo estricto incrementalmente:
// Paso 1: Comienza con strict false pero habilita opciones una por una
{
"compilerOptions": {
"strict": false,
"strictNullChecks": true, // Habilita primero — máximo impacto
"noImplicitAny": true // Habilita segundo
// Agrega más conforme corriges errores
}
}# Cuenta errores restantes para rastrear progreso
npx tsc --noEmit 2>&1 | grep "error TS" | wc -lReglas typescript-eslint que complementan tsconfig:
// Estas reglas ESLint detectan patrones que tsc no marca:
{
rules: {
"@typescript-eslint/no-floating-promises": "error", // Promesas no manejadas
"@typescript-eslint/no-misused-promises": "error", // Promesas en contextos incorrectos
"@typescript-eslint/await-thenable": "error", // await en no-Promise
"@typescript-eslint/no-unnecessary-condition": "warn", // Condiciones siempre-verdaderas
"@typescript-eslint/prefer-nullish-coalescing": "warn", // || vs ??
"@typescript-eslint/strict-boolean-expressions": "warn", // Verificaciones verídicas en no-booleans
},
}Nota: Estas reglas requieren que parserOptions.project esté configurado para linting consciente de tipos.
Notas de TypeScript
// verbatimModuleSyntax fuerza imports de tipo explícitos:
import type { User } from "@/types"; // Solo tipo — borrado en runtime
import { fetchUser } from "@/lib/api"; // Valor — mantenido en runtime
// noUncheckedIndexedAccess en acción:
const items = ["a", "b", "c"];
const first = items[0]; // Tipo: string | undefined (no string)
if (first) {
console.log(first.toUpperCase()); // Seguro — estrechado a string
}
// Sin noUncheckedIndexedAccess:
const risky = items[0]; // Tipo: string (miente — podría ser undefined)
risky.toUpperCase(); // Crash en runtime si el array está vacíoTrampa y Errores Comunes
Cosas que te atraparan. Cada trampa incluye qué sale mal, por qué sucede, y la solución.
-
strictNullChecks crea muchos errores — Habilitar esto en un proyecto grande existente puede producir cientos o miles de errores. Solución: Habilita incrementalmente. Usa
// @ts-expect-errortemporalmente para código seguro conocido y corrige errores archivo por archivo. -
noUncheckedIndexedAccess es ruidoso — Cada
array[i]yobj[key]se convierte enT | undefined, requiriendo verificaciones nulas incluso cuando sabes que el valor existe. Solución: Usa aserción no-nula (items[0]!) esporádicamente donde has verificado que el valor existe, o usa.at(0)con una verificación nula. -
exactOptionalPropertyTypes rompe patrones comunes — Ya no puedes escribir
{ name?: string }y asignarundefinedexplícitamente. Solución: Solo habilita esto si tu código distingue entre propiedades "faltantes" y "explícitamente undefined". La mayoría de proyectos saltan esta opción. -
Las reglas ESLint conscientes de tipos son lentas — Reglas como
no-floating-promisesrequieren información de tipo completa, haciendo ESLint 2 a 5 veces más lento. Solución: Solo habilita reglas conscientes de tipos si el tradeoff vale la pena. Considera ejecutarlas solo en CI, no en el editor. -
verbatimModuleSyntax y CommonJS — Esta opción no funciona bien con módulos CommonJS. Solución: Solo habilítala en proyectos usando módulos ES (que incluye todos los proyectos Next.js App Router).
Alternativas
Otras formas de resolver el mismo problema — y cuándo cada una es la mejor opción.
| Alternativa | Úsalo Cuando | No lo Uses Cuando |
|---|---|---|
strict: false con flags individuales | Migrando un código base grande de JavaScript a TypeScript | Iniciando un proyecto nuevo (solo usa strict: true) |
| Solo reglas ESLint conscientes de tipos | Quieres verificaciones de patrones sin cambiar tsconfig | Necesitas garantías en tiempo de compilación |
// @ts-strict por archivo | Quieres modo estricto en archivos nuevos pero no en código heredado | Puedes habilitarlo a nivel de proyecto |
Preguntas Frecuentes
¿Qué habilita "strict": true?
Habilita ocho flags individuales:
strictNullChecks,strictFunctionTypes,strictBindCallApply,strictPropertyInitializationnoImplicitAny,noImplicitThis,alwaysStrict,useUnknownInCatchVariables
¿Qué opción estricta debo habilitar primero en una código base heredada?
- Comienza con
strictNullChecks-- tiene el mayor impacto y detecta los errores más reales. - Habilita
noImplicitAnysegundo. - Agrega más opciones una por una conforme corriges errores.
¿Qué hace noUncheckedIndexedAccess?
const items = ["a", "b", "c"];
const first = items[0]; // Tipo: string | undefined (no string)
if (first) {
console.log(first.toUpperCase()); // Seguro después de estrechar
}Fuerza verificaciones nulas en cada acceso de índice de array y objeto.
Trampa: ¿Por qué noUncheckedIndexedAccess produce tantos errores?
- Cada
array[i]yobj[key]se convierte enT | undefined. - Debes agregar verificaciones nulas incluso cuando sabes que el valor existe.
- Usa
items[0]!esporádicamente para valores verificados, o usa.at(0)con una verificación.
¿Qué es verbatimModuleSyntax y cuándo debo usarlo?
- Fuerza
import typeexplícito para imports de solo tipo. - Los imports de tipo se borran en runtime; los imports de valor se mantienen.
- Solo habilita en proyectos usando módulos ES (todos los proyectos Next.js App Router califican).
¿Cómo cuento errores de tipo restantes cuando migro?
npx tsc --noEmit 2>&1 | grep "error TS" | wc -lRastrea este número en el tiempo para medir progreso de migración.
¿Cuál es la diferencia entre opciones estrictas de TypeScript y reglas ESLint TypeScript?
- Las opciones estrictas de
tsconfigdetectan problemas a nivel de tipo (seguridad nula, any implícito, desajustes de tipo). - Las reglas
@typescript-eslintdetectan patrones de código (promesas flotantes, condiciones innecesarias, uso any explícito). - Usa ambas para máxima cobertura.
Trampa: ¿Debo habilitar exactOptionalPropertyTypes?
- La mayoría de proyectos saltan esta opción.
- Impide asignar
undefinedexplícitamente a propiedades opcionales. - Solo habilítala si tu código distingue entre propiedades "faltantes" y "explícitamente undefined".
¿Qué son reglas ESLint conscientes de tipos y por qué son lentas?
- Reglas como
no-floating-promisesyno-misused-promisesrequieren información de tipo completa. - ESLint debe invocar el compilador de TypeScript, haciéndolo 2-5x más lento.
- Considera ejecutar reglas conscientes de tipos solo en CI, no en el editor.
¿Por qué Next.js usa noEmit: true en tsconfig?
- Next.js maneja la compilación vía SWC, no el compilador de TypeScript.
tsc --noEmitsolo verifica tipos sin producir archivos de salida.- Esto separa la verificación de tipos del bundling.
¿Cómo funcionan las opciones estrictas de TypeScript con @ts-expect-error?
// @ts-expect-error -- conocido seguro, se arreglará en JIRA-123
const value = riskyFunction();- Usa
@ts-expect-errortemporalmente para código conocido seguro durante migración incremental. - Suprime el error solo en la siguiente línea.
- A diferencia de
@ts-ignore, produce error si el problema suprimido se arregla (manteniendo supresiones honestas).
¿Qué reglas ESLint complementan opciones estrictas de tsconfig?
{
rules: {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/prefer-nullish-coalescing": "warn",
}
}Estas detectan patrones que tsc no marca.
Relacionado
- Reglas ESLint Esenciales — Reglas ESLint que complementan TypeScript estricto
- Plugins ESLint — Configuración del plugin @typescript-eslint
- Linting en CI/CD — ejecutar
tsc --noEmiten CI - Configuración de ESLint para Next.js — configuración base de ESLint