Linting de TypeScript con ESLint
Configuración flat de ESLint 10 para TypeScript: setup con typescript-eslint, lint tipado con projectService y Prettier sin conflictos.
A julio de 2026, la forma actual de aplicar linting a TypeScript es ESLint 10 con el paquete typescript-eslint en flat config (eslint.config.mjs), no la vieja configuración .eslintrc que la mayoría de los resultados de búsqueda siguen mostrando.
Si alguna vez pegaste una configuración de un tutorial de 2022 y viste cómo ESLint la ignoraba por completo, esta es la razón: fue escrita para un sistema de configuración que ya no existe. El reemplazo es breve, aunque la parte de type-aware necesita una opción adicional que es fácil pasar por alto.
ESLint 10 eliminó por completo el sistema de configuración eslintrc, tal como el proyecto había anunciado en sus planes de despliegue de flat config. Ese único cambio rompe casi todos los tutoriales anteriores a 2024, porque ESLint ya no lee en absoluto los archivos .eslintrc ni .eslintignore. Esta guía te ofrece una flat config correcta y lista para copiar y pegar para TypeScript, muestra cómo activar las reglas type-aware e integra el linting en tus scripts, tu editor y tu CI.
Puntos clave
- El stack moderno es ESLint 10 más typescript-eslint v8 en flat config;
.eslintrc/.eslintignoreestán muertos a partir de ESLint 10. - Una configuración mínima pasa
js.configs.recommendedytseslint.configs.recommendedadefineConfig()deeslint/config, en un archivo llamadoeslint.config.js/.mjs. - Las reglas type-aware como
no-floating-promisesnecesitanparserOptions: { projectService: true }. UnparserOptionsvacío no las habilita. - El linting tipado le pide a TypeScript que compile tu proyecto antes del linting, así que es más lento; ejecútalo en CI y confía en el caché del IDE dentro del editor.
- En flat config el flag
--extes obsoleto: la selección de archivos vive en el globfilesde cada bloque, así que el script de lint es simplementeeslint ..
¿ESLint y TypeScript hacen el mismo trabajo?
ESLint y TypeScript son complementarios, no competidores. Un puñado de reglas de typescript-eslint sí recurre al type checker de TypeScript para leer tu código con más profundidad, pero ambas herramientas responden preguntas distintas: el compilador de TypeScript verifica que los tipos encajen, mientras que ESLint impone estilo y detecta bugs probables (variables sin usar, promesas sin manejar, patrones inseguros) en todo tu codebase. Se usan ambos.
Si estás migrando desde TSLint, ten en cuenta que lleva años muerto. Sus responsables anunciaron en 2019 que lo deprecarían en favor de typescript-eslint, y el ecosistema de ESLint se convirtió en el estándar para el linting de TypeScript. No hay razón para recurrir a TSLint en un proyecto nuevo.
Un requisito previo antes de instalar: ESLint 10 dejó de soportar versiones antiguas de Node. Ahora se ejecuta en Node.js v20.19.0 o superior, v22.13.0 o superior, o v24 o superior, y las versiones v21.x y v23.x ya no son compatibles.
¿Cómo se configura ESLint para TypeScript?
Discover how at OpenReplay.com.
Instala los cuatro paquetes que realmente necesitas:
npm i -D eslint @eslint/js typescript typescript-eslint
El helper typescript-eslint empaqueta el parser y el plugin, así que no tienes que conectar @typescript-eslint/parser y @typescript-eslint/eslint-plugin a mano. Es compatible con la major actual: el rango de ESLint documentado por typescript-eslint cubre ^8.57.0 || ^9.0.0 || ^10.0.0, así que typescript-eslint@latest (v8.x) funciona sin problemas sobre ESLint 10.
Crea eslint.config.mjs (flat config, no .eslintrc):
// eslint.config.mjs
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(
js.configs.recommended,
tseslint.configs.recommended,
);
Esa es una base funcional: las reglas recommended del core de ESLint más el conjunto recommended de typescript-eslint, que ya especifica por ti el parser y el plugin de typescript-eslint. defineConfig() viene del core de ESLint y es el helper al que hay que recurrir ahora, porque typescript-eslint ha deprecado su propio tseslint.config() en favor de aquel. El helper antiguo sigue funcionando, así que una configuración que ya funciona no queda rota, pero las nuevas instalaciones deberían usar defineConfig(). En cualquier caso, sigue importando tseslint, ya que aún lo necesitas para tseslint.configs.* y los helpers de globs.
Sube el listón y luego ajusta reglas individuales
recommended es el punto de partida; dos presets opcionales elevan el nivel. tseslint.configs.strict añade reglas de corrección más opinadas, y tseslint.configs.stylistic añade reglas de consistencia que no necesitan información de tipos. Añádelos junto a recommended en el array de configuración.
Sobrescribe cualquier regla en un bloque rules. Las severidades tienen tres niveles: off (o 0) desactiva la regla por completo, warn (o 1) reporta el problema sin afectar el código de salida, y error (o 2) lo reporta y hace que ESLint termine con el código 1. Usa warn para cosas que quieres visibles pero no bloqueantes; usa error para cualquier cosa que no debe llegar al repositorio, ya que sale con código distinto de cero y hace fallar el CI.
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': 'error',
}
En configuraciones modernas, prefiere las severidades en formato string ('warn'/'error') sobre la forma numérica. Se leen con más claridad, y el estilo puramente numérico es un sello distintivo de los tutoriales anticuados de .eslintrc.
Linting type-aware: las reglas que necesitan información de tipos
Algunas de las reglas más valiosas, entre ellas no-floating-promises y no-misused-promises, necesitan información de tipos, y la habilitas añadiendo parserOptions: { projectService: true }. Esa ha sido la forma recomendada de activar el linting tipado desde typescript-eslint v8, reemplazando a la antigua opción project porque requiere menos configuración y se ejecuta más rápido. Cambia también tus presets a sus variantes type-checked (recommendedTypeChecked, strictTypeChecked, stylisticTypeChecked). Un parserOptions: {} vacío no activa el linting type-aware, un error común en configuraciones copiadas.
{
files: ['**/*.ts', '**/*.tsx'],
extends: [tseslint.configs.recommendedTypeChecked],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
}
El linting tipado tiene un costo real. Activarlo significa que TypeScript tiene que compilar tu proyecto antes de que ESLint pueda analizarlo, lo que supone un segundo o dos en un codebase pequeño y bastante más en uno grande. El propio consejo de typescript-eslint se apoya en una asimetría: los plugins de editor cachean la información de tipos y evitan en gran medida la penalización, así que ejecuta el linting tipado completo en CI y en pre-commit, y deja que el editor te cubra en el día a día. projectService también elimina el viejo workaround de mantener un tsconfig.eslint.json aparte, ya que usa el mismo proyecto que usa el editor.
Separa JS de TS y define tus ignores
Las reglas type-checked solo tienen sentido en archivos que TypeScript entiende, así que acótalas a **/*.ts/**/*.tsx y desactívalas para JavaScript plano. typescript-eslint incluye un preset justo para esto. Su propia documentación aplica tseslint.configs.disableTypeChecked a un bloque **/*.js para retirar la configuración específica de TypeScript. En flat config, los ignores son simplemente un bloque de configuración con únicamente una clave ignores, que es lo que sustituye a .eslintignore.
// eslint.config.mjs
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
import prettier from 'eslint-config-prettier';
export default defineConfig(
{ ignores: ['dist/', 'node_modules/', 'coverage/', '**/*.d.ts'] },
js.configs.recommended,
{
files: ['**/*.ts', '**/*.tsx'],
extends: [tseslint.configs.recommendedTypeChecked],
languageOptions: {
parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname },
},
rules: { '@typescript-eslint/no-explicit-any': 'warn' },
},
{ files: ['**/*.js', '**/*.mjs'], extends: [tseslint.configs.disableTypeChecked] },
prettier, // must be last
);
Deja el formateo a Prettier y luego arma el flujo de trabajo
Mantén el formateo fuera de ESLint. Añade eslint-config-prettier al final para desactivar las reglas estilísticas de ESLint que pelearían con Prettier, y fíjalo en ^10.1.8 o posterior. Esa versión importa: en julio de 2025, un ataque de phishing contra las credenciales de npm de un mantenedor derivó en cuatro releases manipuladas, registradas como CVE-2025-54313. Las versiones 8.10.1, 9.1.1, 10.1.6 y 10.1.7 incluían un script postinstall que ejecutaba una carga útil DLL empaquetada en máquinas Windows, y las releases corregidas son 8.10.2, 9.1.2 y 10.1.8. Solo esas cuatro se vieron afectadas y la carga útil solo se ejecutaba en Windows, así que builds anteriores limpias como la 10.1.5 nunca estuvieron comprometidas. Ejecutar Prettier como regla de ESLint mediante eslint-plugin-prettier es posible pero opcional; muchos equipos lo omiten porque hace el linting más lento y ruidoso.
Añade un script de lint. No hace falta el flag --ext, porque la selección de archivos vive en el glob files de cada bloque de configuración:
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix"
}
}
A partir de ahí, ejecuta eslint --fix sobre los archivos en staging con Husky y lint-staged antes de cada commit, habilita fix-on-save en VS Code mediante "source.fixAll.eslint": "explicit" dentro de codeActionsOnSave, y ejecuta eslint . como paso de CI para que una regla fallida bloquee el merge.
Una última cosa que conviene atender: ESLint 9 llegó al fin de su vida útil el 2026-08-06 y no recibe más actualizaciones. Si sigues en ESLint 9, la configuración anterior funciona sin cambios en ESLint 10, así que actualiza el runtime y sigue adelante. Empieza con la configuración mínima de dos líneas, añade recommendedTypeChecked con projectService cuando quieras las reglas de seguridad de promesas, y pon eslint-config-prettier al final.
Preguntas frecuentes
¿Debería habilitar el linting type-aware, y cuál es su costo?
Habilítalo si quieres las reglas de corrección de mayor valor como no-floating-promises y no-misused-promises, que no pueden funcionar sin información de tipos. El costo es que ESLint le pide a TypeScript que compile tu proyecto antes del linting, lo cual es insignificante en proyectos pequeños pero notable en los grandes. La mayoría de los equipos ejecutan el linting tipado completo en CI y en pre-commit, y confían en el caché del IDE dentro del editor, donde se evita la penalización.
¿Cuál es la diferencia entre projectService y project para el linting tipado?
Ambos habilitan el linting tipado, pero projectService es lo que typescript-eslint recomienda a partir de la v8 por su configuración más sencilla y su linting más rápido, porque reutiliza el mismo tsconfig.json que ya usa tu editor. La antigua opción project exige que apuntes a uno o más archivos TSConfig por ruta y a menudo obligaba a los equipos a mantener un tsconfig.eslint.json aparte. Usa projectService: true a menos que tengas una razón específica para no hacerlo.
¿El flag --ext sigue funcionando en la flat config de ESLint?
No, --ext ya no es necesario en flat config. La selección de archivos vive dentro del glob files de cada bloque de configuración, por ejemplo files: ['**/*.ts', '**/*.tsx'], así que ESLint ya sabe qué archivos analizar. Tu script de lint se reduce a eslint . sin flag de extensión. Los scripts que aún pasan --ext están copiados de tutoriales anteriores a flat config, escritos para el sistema eslintrc ya eliminado.
¿Debería usar eslint-config-prettier o eslint-plugin-prettier?
Usa eslint-config-prettier en la mayoría de los proyectos. Desactiva las reglas estilísticas de ESLint que entran en conflicto con Prettier y no añade sobrecarga en tiempo de ejecución; colócalo al final de tu array de configuración. El enfoque de eslint-plugin-prettier ejecuta Prettier como una regla de lint real, lo cual es opcional y más lento, y muestra cada diferencia de formato como un error de lint. Fija eslint-config-prettier en 10.1.8 o posterior para mantenerte al margen del incidente de cadena de suministro de julio de 2025.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k