Rules that promote the use of modern JavaScript features, APIs, and patterns over legacy alternatives.
Modern array methods that provide better performance and readability.
/**
* Prefers Array.flat() over manual array flattening
*/
'unicorn/prefer-array-flat': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
functions?: string[]; // Default: ['concat', 'apply']
}
];
/**
* Prefers Array.flatMap() over map().flat() combination
*/
'unicorn/prefer-array-flat-map': 'error' | 'warn' | 'off';
/**
* Prefers Array.find() over filter()[0] patterns
*/
'unicorn/prefer-array-find': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
checkFromLast?: boolean; // Default: false
}
];
/**
* Prefers Array.some() over find() when checking existence
*/
'unicorn/prefer-array-some': 'error' | 'warn' | 'off';
/**
* Prefers Array.indexOf() over manual iteration for finding indices
*/
'unicorn/prefer-array-index-of': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - manual array flattening
const flattened = [].concat(...arrays);
// ✅ Good - using Array.flat()
const flattened = arrays.flat();
// ❌ Bad - map then flat
const result = items.map(transform).flat();
// ✅ Good - using flatMap
const result = items.flatMap(transform);
// ❌ Bad - filter()[0] pattern
const found = items.filter(item => item.id === id)[0];
// ✅ Good - using find()
const found = items.find(item => item.id === id);Prefers Array.at() and String.at() for accessing elements with negative indices.
/**
* Prefers .at() method for array and string element access
* Particularly useful with negative indices
*/
'unicorn/prefer-at': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
getLastElementFunctions?: string[]; // Default: ['pop', 'shift']
checkAllIndexAccess?: boolean; // Default: false
}
];Usage Examples:
// ❌ Bad - complex negative indexing
const lastItem = array[array.length - 1];
const secondToLast = array[array.length - 2];
// ✅ Good - using .at() method
const lastItem = array.at(-1);
const secondToLast = array.at(-2);
// ❌ Bad - string character access
const lastChar = string[string.length - 1];
// ✅ Good - using .at() for strings
const lastChar = string.at(-1);Modern string methods for better readability and performance.
/**
* Prefers String.includes() over indexOf() !== -1
*/
'unicorn/prefer-includes': 'error' | 'warn' | 'off';
/**
* Prefers String.startsWith() and String.endsWith()
*/
'unicorn/prefer-string-starts-ends-with': 'error' | 'warn' | 'off';
/**
* Prefers String.slice() over String.substr() and String.substring()
*/
'unicorn/prefer-string-slice': 'error' | 'warn' | 'off';
/**
* Prefers String.replaceAll() over String.replace() with global regex
*/
'unicorn/prefer-string-replace-all': 'error' | 'warn' | 'off';
/**
* Prefers String.trimStart() and String.trimEnd() over trimLeft()/trimRight()
*/
'unicorn/prefer-string-trim-start-end': 'error' | 'warn' | 'off';
/**
* Prefers String.raw for template literals with backslashes
*/
'unicorn/prefer-string-raw': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - indexOf() for existence check
if (string.indexOf('substring') !== -1) {
// handle found
}
// ✅ Good - using includes()
if (string.includes('substring')) {
// handle found
}
// ❌ Bad - manual prefix/suffix checking
if (string.indexOf('prefix') === 0) {
// handle prefix
}
// ✅ Good - using startsWith()
if (string.startsWith('prefix')) {
// handle prefix
}
// ❌ Bad - global replace with regex
const result = text.replace(/old/g, 'new');
// ✅ Good - using replaceAll()
const result = text.replaceAll('old', 'new');Modern Date and Math methods for better precision and readability.
/**
* Prefers Date.now() over new Date().getTime()
*/
'unicorn/prefer-date-now': 'error' | 'warn' | 'off';
/**
* Prefers Math.trunc() over bitwise operations for truncation
*/
'unicorn/prefer-math-trunc': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
checkDefaultCase?: boolean; // Default: false
}
];
/**
* Prefers Math.min() and Math.max() over ternary operators
*/
'unicorn/prefer-math-min-max': 'error' | 'warn' | 'off';
/**
* Prefers modern Math APIs over manual implementations
*/
'unicorn/prefer-modern-math-apis': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - verbose date timestamp
const timestamp = new Date().getTime();
// ✅ Good - using Date.now()
const timestamp = Date.now();
// ❌ Bad - bitwise truncation
const truncated = ~~number;
// ✅ Good - using Math.trunc()
const truncated = Math.trunc(number);
// ❌ Bad - ternary for min/max
const min = a < b ? a : b;
// ✅ Good - using Math.min()
const min = Math.min(a, b);Modern DOM methods that replace older patterns.
/**
* Prefers modern DOM APIs over legacy methods
*/
'unicorn/prefer-modern-dom-apis': 'error' | 'warn' | 'off';
/**
* Prefers Node.append() over Node.appendChild()
*/
'unicorn/prefer-dom-node-append': 'error' | 'warn' | 'off';
/**
* Prefers Node.remove() over parentNode.removeChild()
*/
'unicorn/prefer-dom-node-remove': 'error' | 'warn' | 'off';
/**
* Prefers Node.textContent over Node.innerText
*/
'unicorn/prefer-dom-node-text-content': 'error' | 'warn' | 'off';
/**
* Prefers dataset API over getAttribute/setAttribute for data attributes
*/
'unicorn/prefer-dom-node-dataset': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - legacy DOM methods
element.appendChild(child);
parent.removeChild(element);
element.setAttribute('data-value', 'test');
// ✅ Good - modern DOM APIs
element.append(child);
element.remove();
element.dataset.value = 'test';
// ❌ Bad - using innerText
element.innerText = 'Hello';
// ✅ Good - using textContent
element.textContent = 'Hello';Modern Unicode and global object access patterns.
/**
* Prefers String.codePointAt() over String.charCodeAt()
*/
'unicorn/prefer-code-point': 'error' | 'warn' | 'off';
/**
* Prefers globalThis over window, global, or self
*/
'unicorn/prefer-global-this': 'error' | 'warn' | 'off';
/**
* Prefers Number properties over global functions
*/
'unicorn/prefer-number-properties': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
checkInfinity?: boolean; // Default: true
checkNaN?: boolean; // Default: true
}
];Usage Examples:
// ❌ Bad - legacy Unicode handling
const code = string.charCodeAt(0);
// ✅ Good - modern Unicode handling
const code = string.codePointAt(0);
// ❌ Bad - environment-specific global access
const global = window || global || self;
// ✅ Good - using globalThis
const global = globalThis;
// ❌ Bad - global functions
if (isNaN(value)) {
// handle NaN
}
// ✅ Good - Number properties
if (Number.isNaN(value)) {
// handle NaN
}Modern event handling patterns over legacy approaches.
/**
* Prefers addEventListener over on* properties
*/
'unicorn/prefer-add-event-listener': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
excludedPackages?: string[]; // Default: ['koa', 'sax']
}
];
/**
* Prefers EventTarget over other event handling patterns
*/
'unicorn/prefer-event-target': 'error' | 'warn' | 'off';
/**
* Prefers KeyboardEvent.key over KeyboardEvent.keyCode
*/
'unicorn/prefer-keyboard-event-key': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - legacy event handling
element.onclick = handleClick;
// ✅ Good - modern event handling
element.addEventListener('click', handleClick);
// ❌ Bad - legacy keyboard event handling
document.addEventListener('keydown', (event) => {
if (event.keyCode === 13) {
// handle Enter key
}
});
// ✅ Good - modern keyboard event handling
document.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
// handle Enter key
}
});Modern ES module features and import.meta properties.
/**
* Prefers ES modules over CommonJS
*/
'unicorn/prefer-module': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
checkDefaultCase?: boolean; // Default: false
}
];
/**
* Prefers import.meta properties over alternatives
*/
'unicorn/prefer-import-meta-properties': 'error' | 'warn' | 'off';
/**
* Prefers node: protocol for Node.js built-in modules
*/
'unicorn/prefer-node-protocol': 'error' | 'warn' | 'off';
/**
* Prefers export-from syntax when re-exporting
*/
'unicorn/prefer-export-from': 'error' | 'warn' | 'off' | [
'error' | 'warn',
{
ignoreUsedVariables?: boolean; // Default: false
}
];Usage Examples:
// ❌ Bad - CommonJS require
const fs = require('fs');
// ✅ Good - ES module import with node: protocol
import fs from 'node:fs';
// ❌ Bad - __dirname in ES modules
const currentDir = __dirname;
// ✅ Good - import.meta.url
const currentDir = new URL('.', import.meta.url).pathname;
// ❌ Bad - manual re-export
import { helper } from './utils.js';
export { helper };
// ✅ Good - export-from syntax
export { helper } from './utils.js';Modern async patterns using top-level await.
/**
* Prefers top-level await over IIFE patterns
*/
'unicorn/prefer-top-level-await': 'error' | 'warn' | 'off';Usage Examples:
// ❌ Bad - IIFE for async in module scope
(async () => {
const data = await fetchData();
console.log(data);
})();
// ✅ Good - top-level await
const data = await fetchData();
console.log(data);export default [
{
plugins: {
unicorn: eslintPluginUnicorn,
},
rules: {
// Modern array methods
'unicorn/prefer-array-flat': 'error',
'unicorn/prefer-array-flat-map': 'error',
'unicorn/prefer-array-find': 'error',
'unicorn/prefer-array-some': 'error',
'unicorn/prefer-at': 'error',
// Modern string methods
'unicorn/prefer-includes': 'error',
'unicorn/prefer-string-starts-ends-with': 'error',
'unicorn/prefer-string-slice': 'error',
'unicorn/prefer-string-replace-all': 'error',
'unicorn/prefer-string-trim-start-end': 'error',
// Modern APIs
'unicorn/prefer-date-now': 'error',
'unicorn/prefer-math-trunc': 'error',
'unicorn/prefer-global-this': 'error',
'unicorn/prefer-number-properties': 'error',
// Modern modules
'unicorn/prefer-module': 'error',
'unicorn/prefer-node-protocol': 'error',
'unicorn/prefer-top-level-await': 'error',
},
},
];