Mejorando la calidad del código JavaScript con eslint-plugin-unicorn
eslint-plugin-unicorn para ESLint 10: instalación con flat config, presets recommended o unopinionated, y reglas autofixables para mejorar la calidad JS y TS.
eslint-plugin-unicorn es un plugin de ESLint extenso y con criterio propio — más de 300 reglas — que promueve los patrones modernos de JavaScript y TypeScript, detecta errores sutiles de calidad, y la mayoría de sus reglas son autocorregibles. Requiere ESLint >=10.4, configuración plana (flat config) y ESM, lo que significa que la configuración antigua basada en .eslintrc con extends: 'plugin:unicorn/recommended' ya no aplica. Si ya ejecutas ESLint con una configuración básica y quieres elevar la calidad del código sin escribir reglas personalizadas, este plugin es la forma más rápida de lograrlo.
El inconveniente es que tener “criterio propio” es un arma de doble filo. Algunas reglas previenen bucles accidentalmente cuadráticos y errores reales de corrección; otras imponen preferencias estilísticas que chocarán con una base de código ya establecida. Esta guía separa ambos casos: qué impone el plugin, qué reglas valen la pena, cuáles conviene degradar o deshabilitar, y un archivo eslint.config.mjs listo para copiar y pegar que funciona con las herramientas actuales.
Puntos clave
- eslint-plugin-unicorn incluye más de 300 reglas, en su mayoría autocorregibles, y a partir de la v69 (junio de 2026) requiere ESLint ≥10.4, configuración plana y ESM —
.eslintrcya no funciona porque ESLint 10 lo eliminó por completo. - La ruta de adopción más directa: extender
unicorn/recommended, ejecutareslint --fixy luego deshabilitar el puñado de reglas que entran en conflicto con tu base de código — o comenzar desde el presetunopinionated, que ya deshabilita de antemano las reglas más opinativas. - El plugin exporta tres presets:
recommended,unopinionated(recommended sin las reglas opinativas) yall. prefer-set-hasconvierte las búsquedas.includes()-en-un-bucle accidentalmente cuadráticas en comprobaciones O(n) conSet.has(), yno-array-for-eachreescribe.forEach()comofor…ofpara una mejor inferencia de tipos en TypeScript.- Combínalo con
@typescript-eslint/recommended-type-checkedpara unir la aplicación de patrones idiomáticos con el linting con reconocimiento de tipos.
Qué es eslint-plugin-unicorn y cómo funciona
eslint-plugin-unicorn es una colección de reglas de ESLint que orienta el código hacia patrones modernos y menos propensos a errores en JavaScript y TypeScript — prefiriendo la pertenencia a Set sobre el recorrido de arrays, for…of sobre .forEach(), los especificadores de importación node: sobre los nombres de módulo sin prefijo, entre otros. Requiere ESLint >=10.4, configuración plana y ESM. El repositorio se describe a sí mismo como contenedor de más de 300 reglas, y la versión más reciente es la 69.0.0, con publicaciones aproximadamente mensuales.
Dos aspectos de diseño condicionan la forma en que se adopta. Primero, la mayoría de las reglas son autocorregibles, por lo que una gran parte de las infracciones se resuelven con eslint --fix en lugar de edición manual. Segundo, el plugin incluye configuraciones de preset para que no tengas que habilitar las reglas una por una. El plugin exporta una configuración recomendada que aplica buenas prácticas y, por separado, una configuración all que habilita todas las reglas excepto las obsoletas. La tabla de reglas usa emojis para indicar el estado: ✅ para las reglas incluidas en la configuración recomendada, ☑️ para la configuración unopinionated, y 🔧 para las reglas corregibles automáticamente mediante la opción --fix de la CLI.
El alcance es principalmente JavaScript y TypeScript, con una nota útil: aunque la mayoría de las reglas apuntan a JavaScript y TypeScript, algunas también aplican lint a otros tipos de archivo cuando se usan con el plugin de lenguaje de ESLint correspondiente, como @eslint/css, @eslint/json, @eslint/markdown o @html-eslint/eslint-plugin. Para la mayoría de los equipos, las reglas de JS/TS son la razón principal para instalarlo.
Instalación de eslint-plugin-unicorn con configuración plana y ESM
Discover how at OpenReplay.com.
Instala el plugin y una versión compatible de ESLint, luego extiende el preset recomendado dentro de un archivo plano eslint.config.mjs. El requisito actual es ESLint 10.x — ESLint 10 eliminó por completo el sistema eslintrc heredado, dejando la configuración plana como el único formato soportado, por lo que cualquier tutorial que muestre .eslintrc.json con extends: 'plugin:unicorn/recommended' está desactualizado. ESLint requiere una versión actual de Node.js (Node 20.19+, 22.13+, o 24+ según la página de ESLint en npm).
npm install --save-dev eslint eslint-plugin-unicorn
Una configuración mínima funcional con alcance a archivos JavaScript y TypeScript:
// eslint.config.mjs
import unicorn from 'eslint-plugin-unicorn';
import { defineConfig } from 'eslint/config';
export default defineConfig([
{
files: ['**/*.{js,mjs,cjs,ts,tsx}'],
extends: [unicorn.configs.recommended],
rules: {
// las personalizaciones van aquí
},
},
]);
Esto refleja el uso oficial: importar unicorn desde 'eslint-plugin-unicorn', importar {defineConfig} desde 'eslint/config', y luego dentro de defineConfig definir files y extends: [unicorn.configs.recommended]. Delimitar el alcance con files es importante cuando también aplicas lint a lenguajes que no son JavaScript en la misma configuración — mantén las reglas JS de Unicorn en su propio objeto de configuración.
Hay tres presets entre los que elegir tu punto de partida:
recommended— el predeterminado curado.unopinionated— recommended sin las reglas opinativas.all— todas las reglas no obsoletas.
Si tu equipo encuentra las reglas opinativas demasiado ruidosas, reemplaza unicorn.configs.recommended por unicorn.configs.unopinionated y omite gran parte del ajuste manual que se describe más adelante.
Una nota sobre la migración: si aún dependes de un plugin que solo incluye una configuración en estilo eslintrc, envuélvelo con FlatCompat de @eslint/eslintrc. Usa la versión más reciente de @eslint/eslintrc con ESLint 10.x.
Las reglas de eslint-plugin-unicorn de mayor valor, con ejemplos antes y después
Las reglas de Unicorn de mayor valor merecen adoptarse primero porque cada una previene un problema de rendimiento, corrección o legibilidad, en lugar de imponer preferencias estéticas. Cada ejemplo a continuación muestra lo que produce eslint --fix, no código ideal escrito a mano.
prefer-set-has — elimina las búsquedas accidentalmente cuadráticas
prefer-set-has marca un array que solo se usa para comprobaciones de pertenencia con .includes() y te orienta hacia un Set. Prefiere Set#has() sobre Array#includes() al verificar la existencia o no existencia de un elemento. Esto importa especialmente dentro de bucles: Array.prototype.includes es O(n) por llamada, por lo que invocarlo una vez por iteración sobre otra colección resulta en O(n²), mientras que Set.prototype.has es aproximadamente de tiempo constante.
// ❌ O(n²): includes() recorre todo el array en cada iteración
const allowed = ['read', 'write', 'admin', /* …cientos… */];
const granted = requested.filter((scope) => allowed.includes(scope));
// ✅ O(n): Set.has() es aproximadamente de tiempo constante por búsqueda
const allowed = new Set(['read', 'write', 'admin', /* …cientos… */]);
const granted = requested.filter((scope) => allowed.has(scope));
El modo de fallo es silencioso: funciona bien con entradas pequeñas y se degrada notablemente a medida que crecen los datos. Estos son exactamente los problemas de rendimiento en interacciones lentas que terminas diagnosticando en producción en lugar de durante la revisión de código.
no-array-for-each — mejor inferencia de tipos en TypeScript y control de flujo
no-array-for-each reescribe los callbacks de .forEach() como bucles for…of. Prefiere for…of sobre el método forEach. La ventaja va más allá del estilo: for…of ofrece una mejor inferencia de tipos de TypeScript a lo largo del cuerpo del bucle, permite usar await directamente sin las complicaciones de un callback, y soporta break/continue — ninguno de los cuales funciona limpiamente dentro de un callback de .forEach().
// ❌
users.forEach((user) => {
sendEmail(user);
});
// ✅ autocorregido
for (const user of users) {
sendEmail(user);
}
prefer-node-protocol — importaciones de módulos nativos de Node sin ambigüedad
prefer-node-protocol reescribe las importaciones de módulos nativos sin prefijo a la forma explícita node:. Prefiere usar el protocolo node: al importar módulos integrados de Node.js. El prefijo explícito hace que la importación sea inequívocamente un módulo nativo de Node y dificulta que sea eclipsada por un paquete npm con el mismo nombre.
// ❌
import fs from 'fs';
import { join } from 'path';
// ✅ autocorregido
import fs from 'node:fs';
import { join } from 'node:path';
Otras mejoras autocorregibles de valor
Cada una de estas reglas mapea un patrón heredado a su equivalente moderno y se corrige automáticamente:
// throw-new-error — Requiere new al lanzar un error
throw Error('boom'); // ❌
throw new Error('boom'); // ✅
// prefer-string-replace-all — reemplazo global sin regex /g
str.replace(/-/g, ' '); // ❌
str.replaceAll('-', ' '); // ✅
// prefer-array-flat-map — colapsa map().flat()
rows.map((r) => r.cells).flat(); // ❌
rows.flatMap((r) => r.cells); // ✅
// new-for-builtins — requiere new para Map/Set/Array/Date, etc.
const cache = Map(); // ❌
const cache = new Map(); // ✅
La regla throw-new-error requiere new al crear un error (cubriendo tanto const e = Error() como throw Error()), y está incluida en la configuración recomendada y es autocorregible. new-for-builtins impone el uso de new para todos los tipos integrados, excepto String, Number, Boolean, Symbol y BigInt. Array.prototype.flatMap es a la vez más claro y evita el array intermedio que .map().flat() asigna en memoria.
Dos reglas orientadas a la legibilidad completan el conjunto de mayor valor. better-regex mejora las expresiones regulares haciéndolas más cortas y consistentes (por ejemplo, [0-9] se convierte en \d). prefer-ternary colapsa bloques if/else simples: prefiere expresiones ternarias sobre sentencias if simples que retornan o asignan valores. Una sentencia if-else típicamente produce más líneas que un ternario en una sola línea, y puede obligarte a declarar variables con let únicamente para reasignarlas en los bloques — dejándolas innecesariamente mutables e impidiendo que prefer-const marque la variable.
// ❌
function status(ok) {
if (ok) {
return 'pass';
} else {
return 'fail';
}
}
// ✅ autocorregido
function status(ok) {
return ok ? 'pass' : 'fail';
}
Las reglas controvertidas y cómo decidir
Algunas reglas recomendadas imponen preferencias en lugar de corrección, y son las que generan más ruido en una base de código existente. La tabla a continuación presenta la decisión de mantener/advertir/deshabilitar para los casos más habituales, todos habilitados en recommended.
| Regla | Veredicto | Motivo |
|---|---|---|
prevent-abbreviations | Advertir o delimitar alcance | Renombra e → error, req → request, props → properties; entra en conflicto con los nombres que tu framework y tu equipo ya utilizan. |
no-null | Deshabilitar si usas null | Unicorn prefiere undefined, pero null es legítimo cuando un ORM o una API lo devuelve — no hay una única respuesta correcta. |
no-array-reduce | Mantener o advertir | Deshabilita Array#reduce() y Array#reduceRight(); razonable por legibilidad, aunque reduce es perfectamente válido para muchos equipos. |
filename-case | Delimitar con excepciones | Choca con nombres de archivo impuestos por el framework; mantenla pero excluye los casos especiales. |
El caso de no-null es el más claro: Unicorn prefiere undefined, pero null es lo que muchos drivers de bases de datos y APIs HTTP devuelven, por lo que forzar uno sobre el otro genera ruido de conversión sin ningún beneficio en corrección. Deshabilítala cuando null forme parte de tu contrato de datos.
No es necesario deshabilitar estas reglas manualmente. El preset unopinionated deja las reglas opinativas — incluyendo no-null y prevent-abbreviations — deshabilitadas por defecto, por lo que representa el punto medio integrado entre recommended y una configuración muy personalizada.
Para las reglas que conservas pero quieres ajustar, delimita el alcance en lugar de deshabilitar. Un patrón habitual para filename-case excluye los archivos del framework:
{
files: ['**/*.{js,ts,tsx}'],
extends: [unicorn.configs.recommended],
rules: {
'unicorn/no-null': 'off',
'unicorn/prevent-abbreviations': 'warn',
'unicorn/filename-case': [
'error',
{
cases: { pascalCase: true, camelCase: true },
ignore: ['next-env\\.d\\.ts', 'vite\\.config\\.ts'],
},
],
},
}
Adopción incremental en una base de código existente
Despliega el plugin por etapas para que la primera ejecución no te abrume con errores. La secuencia que funciona:
- Comienza desde un preset. Extiende
unicorn/recommended, ounicorn/unopinionatedsi las reglas opinativas resultan demasiado ruidosas para tu equipo. - Autocorrige primero. Ejecuta
npx eslint . --fix. Dado que la mayoría de las reglas son autocorregibles, una gran fracción de las infracciones desaparecerá aquí, y revisarás un único diff mecánico en lugar de cientos de errores en línea. - Degrada las reglas ruidosas a
warn. Cualquier regla que siga disparándose en volumen y no sea un problema de corrección —prevent-abbreviationssuele ser la principal — pásala a'warn'para que no bloquee la CI mientras migras. - Delimita excepciones en lugar de deshabilitar por completo. Usa la opción
ignore(como confilename-case) y globs defilespara definir excepciones en lugar de eliminar una regla útil en todos los contextos. - Incorpora el linting con reconocimiento de tipos. Añade
@typescript-eslint/recommended-type-checkedjunto a Unicorn. Unicorn aplica patrones idiomáticos; la configuracióntype-checkedde typescript-eslint detecta errores que solo el sistema de tipos puede ver. Ambos son complementarios, y habilitarlos juntos es un sólido punto de partida para un proyecto TypeScript.
Trata tu configuración como un documento vivo. A medida que actualices el plugin — las versiones se publican aproximadamente cada mes — revisa la tabla de reglas en busca de nuevas reglas y cambios de nombre, y reconsideras qué reglas en warn están listas para promover a error.
La vía más rápida hacia un mejor JavaScript con eslint-plugin-unicorn no es glamorosa: extiende unicorn/recommended, ejecuta eslint --fix y dedica tu atención únicamente al puñado de reglas opinativas que genuinamente entran en conflicto con la forma en que tu equipo escribe código. Comienza con el preset hoy, deja que el autocorrector haga la mayor parte del trabajo y ajusta desde ahí — la tabla oficial de reglas es la referencia para el estado actual y las opciones de cada regla.
Preguntas frecuentes
¿eslint-plugin-unicorn funciona junto con typescript-eslint o entran en conflicto?
Son complementarios y están diseñados para ejecutarse juntos. Unicorn aplica patrones idiomáticos modernos de JavaScript y TypeScript, mientras que typescript-eslint añade reglas con reconocimiento de tipos que detectan errores que solo el sistema de tipos puede ver. Añade ambos como objetos de configuración separados en tu archivo plano eslint.config.mjs y combina unicorn/recommended con la configuración recommended-type-checked de typescript-eslint. Habilitar ambos es un sólido punto de partida para un proyecto TypeScript, sin superposición de reglas que resolver.
¿Cuál es la diferencia entre los presets recommended y unopinionated?
El preset recommended es el predeterminado curado que habilita tanto las reglas de corrección como las reglas estilísticas opinativas. El preset unopinionated es recommended sin las reglas opinativas, por lo que deshabilita de antemano entradas controvertidas como no-null y prevent-abbreviations que chocan con bases de código ya establecidas. Elige unopinionated cuando tu equipo encuentre las reglas estilísticas demasiado ruidosas; es el punto medio integrado entre recommended y una configuración muy personalizada. Un tercer preset, all, habilita todas las reglas no obsoletas.
¿Por qué deja de funcionar mi antigua configuración .eslintrc con extends plugin:unicorn/recommended?
ESLint 10 eliminó por completo el sistema eslintrc heredado, dejando la configuración plana como el único formato soportado, y eslint-plugin-unicorn requiere ESLint 10.4 o superior, configuración plana y ESM. La sintaxis antigua de .eslintrc con la cadena extends 'plugin:unicorn/recommended' ya no se carga. Migra a un archivo eslint.config.mjs que importe unicorn desde 'eslint-plugin-unicorn' y defina extends como unicorn.configs.recommended dentro de un objeto de configuración delimitado con files.
¿Añadir eslint-plugin-unicorn romperá mi build con cientos de errores?
La mayoría de las infracciones se resuelven automáticamente porque la mayoría de las reglas de unicorn son autocorregibles. Ejecuta eslint con el flag --fix primero, lo que elimina una gran fracción de los problemas como un único diff mecánico en lugar de cientos de errores en línea. Para las reglas que siguen disparándose en volumen pero no son problemas de corrección, como prevent-abbreviations, establécelas en warn para que no bloqueen la CI durante la migración. Este despliegue por etapas mantiene el build en verde mientras adoptas el plugin.