oxlint-config-awesomeness
v1.2.0
Published
Oxlint config with sensible defaults.
Maintainers
Readme
oxlint-config-awesomeness
Opinionated Oxlint config for software houses that want all their apps to feel the same.
493 rules across 10 plugins. Built for full-stack TypeScript monorepos with React, Next.js, Hono, Prisma, and more.
Installation
npm install -D oxlint-config-awesomeness eslint-plugin-no-only-tests eslint-plugin-perfectionist eslint-plugin-react-hooks eslint-plugin-unused-imports[!NOTE] Due to a limitation in Oxlint's configuration resolver, you have to directly install the JS plugins for now.
Usage
In your oxlint.config.ts:
import awesomeness from 'oxlint-config-awesomeness';
import { defineConfig } from 'oxlint';
export default defineConfig({
extends: [awesomeness],
});Then run pnpm oxlint or npx oxlint.
Philosophy
- Error, Never Warn. Warnings are noise. Either it's an issue, or it isn't.
- Category-Based, Future-Proof. Five rule categories (
correctness,suspicious,pedantic,perf,style) are enabled aterror. Restriction rules are cherry-picked individually. New rules from categories are automatically included as oxlint evolves. - Opinionated for Consistency. When multiple approaches exist, this config enforces the strictest option. All apps in your organization will feel the same.
- Smart Overrides. Test files, Storybook stories, seed scripts, config files, and E2E fixtures get relaxed rules where strict enforcement creates noise.
- Formatter-Safe. No formatting rules. Pair with Oxfmt for formatting.
- Prevent Bugs. Debug-only code like
console.logortest.onlyare errors. Missingthrow, bad comparisons, and floating promises are caught automatically.
Plugins
| Plugin | Rules | Description | |--------|-------|-------------| | eslint (core) | 151 | JavaScript best practices and error prevention | | unicorn | 112 | Modern JavaScript patterns and idioms | | typescript | 80 | Strict type safety and TypeScript conventions | | react | 44 | React component rules, hooks, and performance | | jsx-a11y | 30 | Accessibility enforcement for JSX | | import | 21 | Module hygiene and import/export conventions | | nextjs | 21 | Next.js framework best practices | | oxc | 19 | Bug-catching rules unique to oxlint | | promise | 13 | Async/promise handling | | node | 2 | Node.js environment rules |
Plus JS plugins: perfectionist (sorting), react-hooks + React Compiler, no-only-tests, unused-imports.
File-Type Overrides
The config includes smart overrides so strict rules don't create noise in files that need flexibility:
| Files | Relaxed Rules |
|-------|---------------|
| *.test.ts, *.spec.ts, __tests__/** | no-explicit-any, all no-unsafe-*, max-lines, max-statements, no-empty-function |
| *.stories.tsx | no-console, no-multi-comp |
| **/seed.ts, **/migrate.ts | no-console |
| *.config.ts, next.config.*, etc. | max-lines, no-anonymous-default-export |
| **/e2e/**/fixtures/** | rules-of-hooks |
| *.ts, *.tsx (all TypeScript) | Rules handled natively by the TS compiler (no-undef, no-redeclare, etc.) |
Cherry-Picked Restriction Rules
Instead of enabling the entire restriction category (which includes rules like no-bitwise, no-plusplus, capitalized-comments that cause daily friction), this config cherry-picks the most valuable restriction rules:
curly, default-case, eqeqeq, grouped-accessor-pairs, id-length, max-classes-per-file, max-depth, max-lines, max-nested-callbacks, max-params, no-alert, no-caller, no-console, no-eval, no-extend-native, no-implicit-coercion, no-new-func, no-new-wrappers, no-object-constructor, no-param-reassign, no-proto, no-return-assign, no-script-url, no-shadow, no-throw-literal, no-void, prefer-promise-reject-errors, prefer-template
Sorting Rules Disabled
sort-imports, sort-keys, and sort-vars are disabled because sorting is handled by perfectionist (for objects, enums, interfaces, JSX props) and oxfmt (for import ordering).
Unicorn Overrides
| Rule | Setting | Reason |
|------|---------|--------|
| unicorn/filename-case | kebab-case with Next.js exceptions | Allows [slug], [...catchAll], _app patterns |
| unicorn/no-null | off | APIs, JSON, and DOM all return null |
Suggestions
This configuration is meant to be used with:
- TypeScript with strict mode and
noUnusedLocals - Oxfmt for code formatting
- Turborepo for monorepo orchestration
Credits
Based on @nkzw/oxlint-config by Christoph Nakazawa.
All Rules
Every active rule is listed below with a description and code example.
ESLint Core Rules
accessor-pairs
Enforce getter/setter pairs in objects and classes.
// bad
const obj = {
set value(val) { this._value = val; }
};
// good
const obj = {
get value() { return this._value; },
set value(val) { this._value = val; }
};array-callback-return
Enforce return statements in array method callbacks.
// bad
[1, 2, 3].map((x) => {
x * 2;
});
// good
[1, 2, 3].map((x) => x * 2);arrow-body-style
Enforce braces in arrow functions only when needed.
// bad
const fn = () => {
return true;
};
// good
const fn = () => true;block-scoped-var
Enforce that var declarations are used within their defined scope.
// bad
if (true) {
var x = 1;
}
console.log(x);
// good
if (true) {
let x = 1;
console.log(x);
}capitalized-comments
Require the first letter of a comment to be capitalized.
// bad
// this is a comment
// good
// This is a commentclass-methods-use-this
Require class methods to use this or be made static.
// bad
class Foo {
greet() { return 'hello'; }
}
// good
class Foo {
greet() { return this.name; }
}complexity
Enforce a maximum cyclomatic complexity for functions.
// bad
function check(a, b, c, d, e) {
if (a) { if (b) { if (c) { if (d) { if (e) {} } } } }
}
// good
function check(a) {
if (!a) return;
handle(a);
}constructor-super
Require super() calls in constructors of derived classes.
// bad
class Child extends Parent {
constructor() { this.x = 1; }
}
// good
class Child extends Parent {
constructor() { super(); this.x = 1; }
}curly
Require braces around all control-flow bodies.
// bad
if (foo) bar();
// good
if (foo) {
bar();
}default-case
Require a default case in switch statements.
// bad
switch (action) {
case 'run': run(); break;
}
// good
switch (action) {
case 'run': run(); break;
default: idle(); break;
}default-case-last
Enforce default clause to be the last case in switch.
// bad
switch (action) {
default: idle(); break;
case 'run': run(); break;
}
// good
switch (action) {
case 'run': run(); break;
default: idle(); break;
}default-param-last
Enforce default parameters to be last in the parameter list.
// bad
function fn(a = 1, b) {}
// good
function fn(b, a = 1) {}eqeqeq
Require === and !== instead of == and !=.
// bad
if (x == 1) {}
// good
if (x === 1) {}for-direction
Enforce that a for loop update clause moves in the correct direction.
// bad
for (let i = 0; i < 10; i--) {}
// good
for (let i = 0; i < 10; i++) {}func-names
Require named function expressions for better stack traces.
// bad
const foo = function () {};
// good
const foo = function foo() {};func-style
Enforce the use of function expressions over declarations.
// bad
function foo() {}
// good
const foo = function () {};grouped-accessor-pairs
Require getter and setter pairs to be adjacent in objects.
// bad
const obj = {
get a() {},
b: 1,
set a(val) {}
};
// good
const obj = {
get a() {},
set a(val) {},
b: 1
};guard-for-in
Require hasOwnProperty checks in for...in loops.
// bad
for (const key in obj) {
doSomething(key);
}
// good
for (const key in obj) {
if (Object.hasOwn(obj, key)) doSomething(key);
}id-length
Enforce minimum and maximum identifier length.
// bad
const x = 1;
// good
const count = 1;init-declarations
Require variables to be initialized at declaration.
// bad
let count;
count = 0;
// good
let count = 0;max-classes-per-file
Enforce a maximum of one class per file.
// bad
class Foo {}
class Bar {}
// good
// foo.js
class Foo {}max-depth
Enforce a maximum nesting depth of 4.
// bad
if (a) { if (b) { if (c) { if (d) { if (e) {} } } } }
// good
if (!a || !b) return;
if (c && d) handle();max-lines
Enforce a maximum of 400 lines per file (excluding blanks and comments).
// bad
// A file with 500+ lines of code
// good
// Split into focused modules under 400 linesmax-lines-per-function
Enforce a maximum number of lines per function.
// bad
function bigFn() {
// ... 300 lines of logic
}
// good
function smallFn() {
// ... focused, under the limit
}max-nested-callbacks
Enforce a maximum of 3 nested callbacks.
// bad
fn(() => { fn(() => { fn(() => { fn(() => {}); }); }); });
// good
const inner = () => {};
const middle = () => fn(inner);
fn(middle);max-params
Enforce a maximum of 4 parameters per function.
// bad
function fn(a, b, c, d, e) {}
// good
function fn({ a, b, c, d, e }) {}max-statements
Enforce a maximum number of statements per function.
// bad
function fn() {
// ... 50 statements
}
// good
function fn() {
// ... focused, fewer statements
}new-cap
Require constructor names to begin with a capital letter.
// bad
const thing = new myObject();
// good
const thing = new MyObject();no-alert
Disallow alert, confirm, and prompt.
// bad
alert('done');
// good
showNotification('done');no-array-constructor
Disallow the Array constructor.
// bad
const arr = new Array(1, 2, 3);
// good
const arr = [1, 2, 3];no-async-promise-executor
Disallow using async function as a Promise executor.
// bad
const p = new Promise(async (resolve) => {
resolve(await fetch(url));
});
// good
const p = fetch(url);no-await-in-loop
Disallow await inside loops. Use Promise.all instead.
// bad
for (const url of urls) {
await fetch(url);
}
// good
await Promise.all(urls.map((url) => fetch(url)));no-bitwise
Disallow bitwise operators.
// bad
const flags = a | b;
// good
const flags = a || b;no-caller
Disallow arguments.caller and arguments.callee.
// bad
function fn() { return arguments.callee; }
// good
function fn() { return fn; }no-case-declarations
Disallow lexical declarations in case clauses without blocks.
// bad
switch (x) {
case 0:
let result = calc();
}
// good
switch (x) {
case 0: {
let result = calc();
}
}no-class-assign
Disallow reassigning class declarations.
// bad
class Foo {}
Foo = 'bar';
// good
class Foo {}
const bar = 'bar';no-compare-neg-zero
Disallow comparing against -0.
// bad
if (x === -0) {}
// good
if (Object.is(x, -0)) {}no-cond-assign
Disallow assignment operators in conditional statements.
// bad
if (x = 0) {}
// good
if (x === 0) {}no-console
Disallow console usage in production code.
// bad
console.log('debug');
// good
logger.info('debug');no-const-assign
Disallow reassigning const variables.
// bad
const x = 1;
x = 2;
// good
let x = 1;
x = 2;no-constant-binary-expression
Disallow expressions where the operation does not affect the value.
// bad
const result = x ?? 'default' || 'fallback';
// good
const result = (x ?? 'default') || 'fallback';no-constant-condition
Disallow constant expressions in conditions.
// bad
if (true) {}
// good
if (isReady) {}no-constructor-return
Disallow returning a value from a constructor.
// bad
class Foo {
constructor() { return {}; }
}
// good
class Foo {
constructor() { this.x = 1; }
}no-continue
Disallow continue statements.
// bad
for (const x of items) {
if (!x) continue;
process(x);
}
// good
for (const x of items) {
if (x) process(x);
}no-control-regex
Disallow control characters in regular expressions.
// bad
const re = /\x1f/;
// good
const re = /\n/;no-debugger
Disallow the debugger statement.
// bad
debugger;
// good
// Use browser devtools breakpoints insteadno-delete-var
Disallow deleting variables.
// bad
let x = 1;
delete x;
// good
let x = 1;
x = undefined;no-div-regex
Disallow division operators at the start of regular expressions.
// bad
const re = /=foo/;
// good
const re = /[=]foo/;no-dupe-class-members
Disallow duplicate class members.
// bad
class Foo {
bar() {}
bar() {}
}
// good
class Foo {
bar() {}
baz() {}
}no-dupe-else-if
Disallow duplicate conditions in else-if chains.
// bad
if (a) {} else if (a) {}
// good
if (a) {} else if (b) {}no-dupe-keys
Disallow duplicate keys in object literals.
// bad
const obj = { a: 1, a: 2 };
// good
const obj = { a: 1, b: 2 };no-duplicate-case
Disallow duplicate case labels in switch.
// bad
switch (x) {
case 1: break;
case 1: break;
}
// good
switch (x) {
case 1: break;
case 2: break;
}no-duplicate-imports
Disallow duplicate module imports.
// bad
import { a } from 'mod';
import { b } from 'mod';
// good
import { a, b } from 'mod';no-else-return
Disallow else blocks after return in if.
// bad
if (x) { return a; } else { return b; }
// good
if (x) { return a; }
return b;no-empty
Disallow empty block statements.
// bad
if (condition) {}
// good
if (condition) {
handleCase();
}no-empty-character-class
Disallow empty character classes in regular expressions.
// bad
const re = /abc[]/;
// good
const re = /abc[a-z]/;no-empty-function
Disallow empty functions.
// bad
function noop() {}
// good
function noop() { /* Intentionally empty */ }no-empty-pattern
Disallow empty destructuring patterns.
// bad
const {} = obj;
// good
const { a } = obj;no-empty-static-block
Disallow empty static blocks in classes.
// bad
class Foo { static {} }
// good
class Foo { static { this.count = 0; } }no-eq-null
Disallow == null comparisons.
// bad
if (x == null) {}
// good
if (x === null || x === undefined) {}no-eval
Disallow eval().
// bad
eval('alert("hi")');
// good
alert('hi');no-ex-assign
Disallow reassigning exceptions in catch clauses.
// bad
try {} catch (e) { e = new Error(); }
// good
try {} catch (e) { const wrapped = new Error(); }no-extend-native
Disallow extending native objects.
// bad
Array.prototype.first = function () {};
// good
function first(arr) { return arr[0]; }no-extra-bind
Disallow unnecessary .bind() calls.
// bad
const fn = function () { return 1; }.bind(this);
// good
const fn = function () { return 1; };no-extra-boolean-cast
Disallow unnecessary boolean casts.
// bad
if (!!x) {}
// good
if (x) {}no-extra-label
Disallow unnecessary labels.
// bad
outer: while (true) { break outer; }
// good
while (true) { break; }no-fallthrough
Disallow fallthrough of case statements.
// bad
switch (x) {
case 1:
doA();
case 2:
doB();
}
// good
switch (x) {
case 1:
doA();
break;
case 2:
doB();
break;
}no-func-assign
Disallow reassigning function declarations.
// bad
function foo() {}
foo = bar;
// good
function foo() {}
const baz = bar;no-global-assign
Disallow assignments to native objects or read-only global variables.
// bad
undefined = 1;
// good
const myUndefined = 1;no-implicit-coercion
Disallow shorthand type conversions.
// bad
const str = '' + value;
const num = +value;
// good
const str = String(value);
const num = Number(value);no-import-assign
Disallow assigning to imported bindings.
// bad
import { x } from 'mod';
x = 1;
// good
import { x } from 'mod';
const y = 1;no-inline-comments
Disallow inline comments after code.
// bad
const x = 1; // inline comment
// good
// Comment above
const x = 1;no-inner-declarations
Disallow variable or function declarations in nested blocks.
// bad
if (test) {
function doSomething() {}
}
// good
function doSomething() {}
if (test) { doSomething(); }no-invalid-regexp
Disallow invalid regular expression strings in RegExp constructors.
// bad
new RegExp('[');
// good
new RegExp('[a-z]');no-irregular-whitespace
Disallow irregular whitespace characters.
// bad
const desc = 'foo\u00A0bar';
// good
const desc = 'foo bar';no-iterator
Disallow the __iterator__ property.
// bad
Foo.prototype.__iterator__ = function () {};
// good
Foo.prototype[Symbol.iterator] = function () {};no-label-var
Disallow labels that share a name with a variable.
// bad
let x = 1;
x: while (true) { break x; }
// good
loop: while (true) { break loop; }no-labels
Disallow labeled statements.
// bad
outer: for (;;) { break outer; }
// good
for (;;) { break; }no-lone-blocks
Disallow unnecessary nested blocks.
// bad
{ const x = 1; }
// good
const x = 1;no-lonely-if
Disallow if as the only statement in an else block.
// bad
if (a) {} else { if (b) {} }
// good
if (a) {} else if (b) {}no-loop-func
Disallow functions inside loops that reference loop variables.
// bad
for (var i = 0; i < 5; i++) {
fns.push(() => i);
}
// good
for (let i = 0; i < 5; i++) {
fns.push(() => i);
}no-loss-of-precision
Disallow number literals that lose precision.
// bad
const x = 9007199254740993;
// good
const x = 9007199254740992n;no-misleading-character-class
Disallow characters composed of multiple code points in character classes.
// bad
const re = /[👶🏻]/;
// good
const re = /👶🏻/u;no-multi-assign
Disallow chained assignment expressions.
// bad
let a = b = c = 1;
// good
let a = 1;
let b = 1;
let c = 1;no-multi-str
Disallow multiline strings using backslash.
// bad
const str = 'line1 \
line2';
// good
const str = 'line1\nline2';no-negated-condition
Disallow negated conditions when an else is present.
// bad
if (!x) { a(); } else { b(); }
// good
if (x) { b(); } else { a(); }no-nested-ternary
Disallow nested ternary expressions.
// bad
const x = a ? b ? c : d : e;
// good
const inner = b ? c : d;
const x = a ? inner : e;no-new
Disallow new operators outside of assignments or comparisons.
// bad
new SideEffect();
// good
const instance = new SideEffect();no-new-func
Disallow the Function constructor.
// bad
const fn = new Function('a', 'return a');
// good
const fn = (a) => a;no-new-native-nonconstructor
Disallow new operators with Symbol and BigInt.
// bad
const sym = new Symbol('desc');
// good
const sym = Symbol('desc');no-new-wrappers
Disallow primitive wrapper instances (new String, new Number, new Boolean).
// bad
const str = new String('hello');
// good
const str = 'hello';no-nonoctal-decimal-escape
Disallow \8 and \9 escape sequences in string literals.
// bad
const str = '\8';
// good
const str = '8';no-obj-calls
Disallow calling global objects as functions.
// bad
const math = Math();
// good
const pi = Math.PI;no-object-constructor
Disallow the Object constructor without arguments.
// bad
const obj = new Object();
// good
const obj = {};no-param-reassign
Disallow reassigning function parameters.
// bad
function fn(x) { x = 10; }
// good
function fn(x) { const y = 10; }no-plusplus
Disallow the unary ++ and -- operators.
// bad
let i = 0;
i++;
// good
let i = 0;
i += 1;no-promise-executor-return
Disallow returning values from Promise executor functions.
// bad
new Promise((resolve) => resolve(1));
// good
new Promise((resolve) => { resolve(1); });no-proto
Disallow the __proto__ property.
// bad
const proto = obj.__proto__;
// good
const proto = Object.getPrototypeOf(obj);no-prototype-builtins
Disallow calling Object.prototype methods directly on objects.
// bad
obj.hasOwnProperty('key');
// good
Object.hasOwn(obj, 'key');no-redeclare
Disallow variable redeclaration.
// bad
var x = 1;
var x = 2;
// good
let x = 1;
x = 2;no-regex-spaces
Disallow multiple spaces in regular expressions.
// bad
const re = /foo bar/;
// good
const re = /foo {3}bar/;no-restricted-globals
Disallow specified global variables.
// bad
event.preventDefault();
// good
function handler(event) { event.preventDefault(); }no-restricted-imports
Disallow specified modules when loaded by import.
// bad
import _ from 'lodash';
// good
import groupBy from 'lodash/groupBy';no-return-assign
Disallow assignment operators in return statements.
// bad
const fn = () => result = value;
// good
const fn = () => { result = value; };no-script-url
Disallow javascript: URLs.
// bad
location.href = 'javascript:void(0)';
// good
location.href = '#';no-self-assign
Disallow assignments where both sides are exactly the same.
// bad
x = x;
// good
x = y;no-self-compare
Disallow comparisons where both sides are exactly the same.
// bad
if (x === x) {}
// good
if (Number.isNaN(x)) {}no-sequences
Disallow comma operators.
// bad
const x = (doSomething(), val);
// good
doSomething();
const x = val;no-setter-return
Disallow returning values from setters.
// bad
const obj = { set x(val) { return val; } };
// good
const obj = { set x(val) { this._x = val; } };no-shadow
Disallow variable declarations from shadowing outer scope variables.
// bad
const x = 1;
function fn() { const x = 2; }
// good
const x = 1;
function fn() { const y = 2; }no-shadow-restricted-names
Disallow shadowing restricted identifiers like undefined, NaN, Infinity.
// bad
const undefined = 'foo';
// good
const undef = 'foo';no-sparse-arrays
Disallow sparse arrays.
// bad
const arr = [1, , 3];
// good
const arr = [1, undefined, 3];no-template-curly-in-string
Disallow template literal placeholder syntax in regular strings.
// bad
const msg = 'Hello ${name}';
// good
const msg = `Hello ${name}`;no-this-before-super
Disallow this/super before calling super() in constructors.
// bad
class A extends B {
constructor() { this.x = 1; super(); }
}
// good
class A extends B {
constructor() { super(); this.x = 1; }
}no-throw-literal
Require throwing Error objects only.
// bad
throw 'error';
// good
throw new Error('error');no-unassigned-vars
Disallow variables that are declared but never assigned.
// bad
let x;
console.log(x);
// good
const x = 0;
console.log(x);no-unexpected-multiline
Disallow confusing multiline expressions.
// bad
const foo = bar
(1 + 2).toString();
// good
const foo = bar;
(1 + 2).toString();no-unmodified-loop-condition
Disallow unmodified conditions in loops.
// bad
let x = true;
while (x) { doSomething(); }
// good
let x = true;
while (x) { x = doSomething(); }no-unneeded-ternary
Disallow ternary operators when simpler alternatives exist.
// bad
const isYes = answer === 1 ? true : false;
// good
const isYes = answer === 1;no-unsafe-finally
Disallow control flow statements in finally blocks.
// bad
try {} finally { return 1; }
// good
try {} finally { cleanup(); }no-unsafe-negation
Disallow negating the left operand of relational operators.
// bad
if (!key in object) {}
// good
if (!(key in object)) {}no-unsafe-optional-chaining
Disallow optional chaining in contexts where undefined is not allowed.
// bad
const result = (obj?.foo)();
// good
const result = obj?.foo?.();no-unused-expressions
Disallow unused expressions.
// bad
x + 1;
// good
const result = x + 1;no-unused-labels
Disallow unused labels.
// bad
OUTER: for (;;) { break; }
// good
for (;;) { break; }no-unused-private-class-members
Disallow unused private class members.
// bad
class Foo { #unused = 1; }
// good
class Foo {
#count = 0;
increment() { this.#count += 1; }
}no-unused-vars
Disallow unused variables.
// bad
const unused = 1;
// good
const used = 1;
console.log(used);no-use-before-define
Disallow using variables before they are defined.
// bad
console.log(x);
const x = 1;
// good
const x = 1;
console.log(x);no-useless-backreference
Disallow useless backreferences in regular expressions.
// bad
const re = /(?:a)\1/;
// good
const re = /(a)\1/;no-useless-call
Disallow unnecessary .call() and .apply().
// bad
fn.call(undefined, arg);
// good
fn(arg);no-useless-catch
Disallow catch clauses that only rethrow.
// bad
try { doSomething(); } catch (e) { throw e; }
// good
doSomething();no-useless-computed-key
Disallow unnecessary computed property keys.
// bad
const obj = { ['a']: 1 };
// good
const obj = { a: 1 };no-useless-concat
Disallow unnecessary concatenation of strings.
// bad
const str = 'a' + 'b';
// good
const str = 'ab';no-useless-constructor
Disallow unnecessary constructors.
// bad
class Foo { constructor() {} }
// good
class Foo {}no-useless-escape
Disallow unnecessary escape characters.
// bad
const str = '\"';
// good
const str = '"';no-useless-rename
Disallow renaming import, export, and destructured assignments to the same name.
// bad
import { foo as foo } from 'mod';
// good
import { foo } from 'mod';no-useless-return
Disallow redundant return statements.
// bad
function fn() { doSomething(); return; }
// good
function fn() { doSomething(); }no-var
Require let or const instead of var.
// bad
var x = 1;
// good
const x = 1;no-void
Disallow the void operator.
// bad
void 0;
// good
undefined;no-warning-comments
Disallow comments containing @nocommit.
// bad
// @nocommit temporary hack
// good
// TODO: refactor this laterno-with
Disallow with statements.
// bad
with (obj) { foo = 1; }
// good
obj.foo = 1;operator-assignment
Require shorthand operators where possible.
// bad
x = x + 1;
// good
x += 1;prefer-const
Require const for variables that are never reassigned.
// bad
let x = 1;
// good
const x = 1;prefer-destructuring
Require destructuring from arrays and objects.
// bad
const x = arr[0];
const y = obj.y;
// good
const [x] = arr;
const { y } = obj;prefer-exponentiation-operator
Require ** instead of Math.pow().
// bad
const sq = Math.pow(x, 2);
// good
const sq = x ** 2;prefer-numeric-literals
Require binary, octal, and hexadecimal literals instead of parseInt().
// bad
const x = parseInt('111110111', 2);
// good
const x = 0b111110111;prefer-object-has-own
Require Object.hasOwn() over Object.prototype.hasOwnProperty.call().
// bad
Object.prototype.hasOwnProperty.call(obj, 'key');
// good
Object.hasOwn(obj, 'key');prefer-object-spread
Require spread syntax instead of Object.assign().
// bad
const obj = Object.assign({}, defaults, overrides);
// good
const obj = { ...defaults, ...overrides };prefer-promise-reject-errors
Require Error objects as Promise rejection reasons.
// bad
Promise.reject('error');
// good
Promise.reject(new Error('error'));prefer-rest-params
Require rest parameters instead of arguments.
// bad
function fn() { return arguments; }
// good
function fn(...args) { return args; }prefer-spread
Require spread syntax instead of .apply().
// bad
Math.max.apply(Math, nums);
// good
Math.max(...nums);prefer-template
Require template literals instead of string concatenation.
// bad
const msg = 'Hello ' + name;
// good
const msg = `Hello ${name}`;preserve-caught-error
Require a parameter in catch clauses.
// bad
try {} catch { handleError(); }
// good
try {} catch (error) { handleError(error); }radix
Require the radix parameter in parseInt().
// bad
parseInt('071');
// good
parseInt('071', 10);require-await
Disallow async functions that have no await expression.
// bad
async function fn() { return 1; }
// good
async function fn() { return await fetchData(); }require-yield
Require yield in generator functions.
// bad
function* gen() { return 1; }
// good
function* gen() { yield 1; }symbol-description
Require a description when creating Symbol.
// bad
const sym = Symbol();
// good
const sym = Symbol('id');unicode-bom
Disallow Unicode byte order mark (BOM).
// bad
\uFEFFconst x = 1;
// good
const x = 1;use-isnan
Require Number.isNaN() instead of comparison with NaN.
// bad
if (x === NaN) {}
// good
if (Number.isNaN(x)) {}valid-typeof
Enforce comparing typeof expressions against valid strings.
// bad
typeof x === 'strig';
// good
typeof x === 'string';vars-on-top
Require var declarations to be at the top of their scope.
// bad
function fn() {
doSomething();
var x = 1;
}
// good
function fn() {
var x = 1;
doSomething();
}yoda
Disallow Yoda conditions.
// bad
if ('red' === color) {}
// good
if (color === 'red') {}TypeScript Rules
@typescript-eslint/adjacent-overload-signatures
Require overload signatures to be consecutive.
// bad
declare function foo(x: string): void;
declare function bar(): void;
declare function foo(x: number): void;
// good
declare function foo(x: string): void;
declare function foo(x: number): void;
declare function bar(): void;@typescript-eslint/array-type
Enforce using generic Array<T> syntax over T[].
// bad
const items: string[] = [];
// good
const items: Array<string> = [];@typescript-eslint/ban-ts-comment
Disallow @ts-ignore, @ts-nocheck, and @ts-check comments.
// bad
// @ts-ignore
const x: number = 'hello';
// good
const x: number = Number('hello');@typescript-eslint/ban-tslint-comment
Disallow // tslint:<rule> comments.
// bad
// tslint:disable-next-line
// good
// eslint-disable-next-line@typescript-eslint/ban-types
Disallow certain types like Object, String, Number, Boolean.
// bad
const fn = (x: Object) => {};
// good
const fn = (x: Record<string, unknown>) => {};@typescript-eslint/class-literal-property-style
Enforce using readonly fields over getters that return literals.
// bad
class Foo {
get name() { return 'foo'; }
}
// good
class Foo {
readonly name = 'foo';
}@typescript-eslint/consistent-generic-constructors
Enforce specifying type parameters on the constructor call, not the variable type.
// bad
const map: Map<string, number> = new Map();
// good
const map = new Map<string, number>();@typescript-eslint/consistent-indexed-object-style
Enforce using Record<K, V> over index signatures.
// bad
type Foo = { [key: string]: number };
// good
type Foo = Record<string, number>;@typescript-eslint/consistent-type-definitions
Enforce using type over interface.
// bad
interface User {
name: string;
}
// good
type User = {
name: string;
};@typescript-eslint/consistent-type-imports
Enforce consistent usage of type imports.
// bad
import { User } from './types';
// good
import type { User } from './types';@typescript-eslint/default-param-last
Enforce default parameters to be last (TypeScript version).
// bad
function fn(a: number = 1, b: number) {}
// good
function fn(b: number, a: number = 1) {}@typescript-eslint/explicit-function-return-type
Require explicit return types on functions and class methods.
// bad
const fn = () => 'hello';
// good
const fn = (): string => 'hello';@typescript-eslint/explicit-member-accessibility
Require explicit accessibility modifiers on class properties and methods.
// bad
class Foo { x = 1; }
// good
class Foo { public x = 1; }@typescript-eslint/explicit-module-boundary-types
Require explicit return and argument types on exported functions.
// bad
export const fn = (x) => x + 1;
// good
export const fn = (x: number): number => x + 1;@typescript-eslint/member-ordering
Enforce a consistent member declaration order.
// bad
class Foo {
method() {}
public x = 1;
}
// good
class Foo {
public x = 1;
method() {}
}@typescript-eslint/method-signature-style
Enforce using property-style method signatures.
// bad
type Foo = {
bar(x: number): void;
};
// good
type Foo = {
bar: (x: number) => void;
};@typescript-eslint/naming-convention
Enforce naming conventions for identifiers.
// bad
const my_var = 1;
type myType = string;
// good
const myVar = 1;
type MyType = string;@typescript-eslint/no-confusing-non-null-assertion
Disallow non-null assertions in confusing positions.
// bad
const x = foo!.bar;
// good
const x = foo?.bar;@typescript-eslint/no-confusing-void-expression
Require expressions of type void to appear in statement position.
// bad
const x = alert('hi');
// good
alert('hi');@typescript-eslint/no-deprecated
Disallow usage of deprecated APIs.
// bad
/** @deprecated Use newFn instead */
declare function oldFn(): void;
oldFn();
// good
newFn();@typescript-eslint/no-dupe-class-members
Disallow duplicate class members (TypeScript version).
// bad
class Foo {
bar() {}
bar() {}
}
// good
class Foo {
bar() {}
baz() {}
}@typescript-eslint/no-duplicate-enum-values
Disallow duplicate enum member values.
// bad
enum E { A = 1, B = 1 }
// good
enum E { A = 1, B = 2 }@typescript-eslint/no-dynamic-delete
Disallow using the delete operator on computed key expressions.
// bad
delete obj[key];
// good
Reflect.deleteProperty(obj, key);@typescript-eslint/no-empty-function
Disallow empty functions (TypeScript version).
// bad
function noop(): void {}
// good
function noop(): void { /* Intentionally empty */ }@typescript-eslint/no-empty-interface
Disallow empty interfaces.
// bad
interface Empty {}
// good
type Empty = Record<string, never>;@typescript-eslint/no-empty-object-type
Disallow {} as a type.
// bad
type Foo = {};
// good
type Foo = Record<string, unknown>;@typescript-eslint/no-explicit-any
Disallow the any type.
// bad
const x: any = {};
// good
const x: unknown = {};@typescript-eslint/no-extra-non-null-assertion
Disallow extra non-null assertions.
// bad
const x = foo!!.bar;
// good
const x = foo!.bar;@typescript-eslint/no-extraneous-class
Disallow classes with only static members.
// bad
class Utils {
static format() {}
}
// good
export const format = () => {};@typescript-eslint/no-floating-promises
Require Promise-like statements to be handled.
// bad
fetchData();
// good
await fetchData();@typescript-eslint/no-for-in-array
Disallow iterating over arrays with for...in.
// bad
for (const i in arr) {}
// good
for (const item of arr) {}@typescript-eslint/no-import-type-side-effects
Enforce that type-only imports have inline type qualifiers.
// bad
import type { A, B } from 'mod';
// good
import { type A, type B } from 'mod';@typescript-eslint/no-inferrable-types
Disallow explicit types where they can be trivially inferred.
// bad
const x: number = 1;
// good
const x = 1;@typescript-eslint/no-loop-func
Disallow functions created inside loops (TypeScript version).
// bad
for (let i = 0; i < 5; i++) {
fns.push(() => i);
}
// good
const makeFn = (i: number) => () => i;
for (let i = 0; i < 5; i++) { fns.push(makeFn(i)); }@typescript-eslint/no-loss-of-precision
Disallow number literals that lose precision (TypeScript version).
// bad
const x = 9007199254740993;
// good
const x = 9007199254740992n;@typescript-eslint/no-magic-numbers
Disallow magic numbers. Disabled in this config.
@typescript-eslint/no-meaningless-void-operator
Disallow the void operator except where it is useful.
// bad
void someValue;
// good
void someAsyncOperation();@typescript-eslint/no-misused-new
Enforce valid definitions of new and constructor.
// bad
interface Foo {
new (): Foo;
}
// good
class Foo {
constructor() {}
}@typescript-eslint/no-misused-promises
Disallow Promises in places not designed to handle them.
// bad
if (fetchData()) {}
// good
if (await fetchData()) {}@typescript-eslint/no-mixed-enums
Disallow enums from mixing string and number members.
// bad
enum E { A = 0, B = 'b' }
// good
enum E { A = 'a', B = 'b' }@typescript-eslint/no-namespace
Disallow TypeScript namespaces.
// bad
namespace Foo { export const x = 1; }
// good
export const x = 1;@typescript-eslint/no-non-null-asserted-nullish-coalescing
Disallow non-null assertions with nullish coalescing.
// bad
const x = foo! ?? bar;
// good
const x = foo ?? bar;@typescript-eslint/no-non-null-asserted-optional-chain
Disallow non-null assertions after optional chaining.
// bad
const x = foo?.bar!;
// good
const x = foo?.bar;@typescript-eslint/no-non-null-assertion
Disallow non-null assertions using !.
// bad
const x = value!;
// good
const x = value ?? fallback;@typescript-eslint/no-redeclare
Disallow variable redeclaration (TypeScript version).
// bad
let x = 1;
let x = 2;
// good
let x = 1;
x = 2;@typescript-eslint/no-require-imports
Disallow require() calls.
// bad
const fs = require('fs');
// good
import fs from 'fs';@typescript-eslint/no-restricted-imports
Disallow specified modules when loaded by import (TypeScript version).
// bad
import _ from 'lodash';
// good
import groupBy from 'lodash/groupBy';@typescript-eslint/no-shadow
Disallow variable shadowing (TypeScript version).
// bad
const x = 1;
const fn = () => { const x = 2; };
// good
const x = 1;
const fn = () => { const y = 2; };@typescript-eslint/no-this-alias
Disallow aliasing this.
// bad
const self = this;
// good
const fn = () => this.value;@typescript-eslint/no-type-alias
Disallow type aliases in favor of interfaces. Superseded by consistent-type-definitions.
// bad
type Name = string;
// good
type User = { name: string };@typescript-eslint/no-unnecessary-boolean-literal-compare
Disallow unnecessary equality comparison against boolean literals.
// bad
if (isReady === true) {}
// good
if (isReady) {}@typescript-eslint/no-unnecessary-condition
Disallow conditionals where the type is always truthy or always falsy.
// bad
const x = 'hello';
if (x) {}
// good
const x = getValue();
if (x) {}@typescript-eslint/no-unnecessary-qualifier
Disallow unnecessary namespace qualifiers.
// bad
namespace Foo {
export type Bar = string;
const x: Foo.Bar = 'hi';
}
// good
namespace Foo {
export type Bar = string;
const x: Bar = 'hi';
}@typescript-eslint/no-unnecessary-type-arguments
Disallow type arguments that are equal to the default.
// bad
const p = new Promise<unknown>((resolve) => resolve());
// good
const p = new Promise((resolve) => resolve());@typescript-eslint/no-unnecessary-type-assertion
Disallow type assertions that do not change the type.
// bad
const x = 'hello' as string;
// good
const x = 'hello';@typescript-eslint/no-unnecessary-type-constraint
Disallow unnecessary constraints on generic types.
// bad
type Foo<T extends unknown> = T;
// good
type Foo<T> = T;@typescript-eslint/no-unnecessary-type-parameters
Disallow type parameters that are only used once.
// bad
function fn<T>(x: T): void {}
// good
function fn(x: unknown): void {}@typescript-eslint/no-unsafe-argument
Disallow calling a function with a value of type any.
// bad
const x: any = {};
fn(x);
// good
const x: unknown = {};
fn(x as ExpectedType);@typescript-eslint/no-unsafe-assignment
Disallow assigning a value with type any.
// bad
const x: string = someAny;
// good
const x: string = someAny as string;@typescript-eslint/no-unsafe-call
Disallow calling a value with type any.
// bad
const x: any = () => {};
x();
// good
const x: () => void = () => {};
x();@typescript-eslint/no-unsafe-declaration-merging
Disallow unsafe declaration merging.
// bad
interface Foo {}
class Foo {}
// good
class Foo {}@typescript-eslint/no-unsafe-enum-comparison
Disallow comparing an enum value with a non-enum value.
// bad
enum Status { Active }
if (status === 0) {}
// good
enum Status { Active }
if (status === Status.Active) {}@typescript-eslint/no-unsafe-member-access
Disallow member access on a value with type any.
// bad
const x: any = {};
x.foo;
// good
const x: Record<string, unknown> = {};
x.foo;@typescript-eslint/no-unsafe-return
Disallow returning a value with type any.
// bad
function fn(): string { return anyValue; }
// good
function fn(): string { return String(anyValue); }@typescript-eslint/no-unsafe-unary-minus
Disallow unary minus on non-numeric types.
// bad
const x: any = '5';
const y = -x;
// good
const x = 5;
const y = -x;@typescript-eslint/no-unused-expressions
Disallow unused expressions (TypeScript version).
// bad
x + 1;
// good
const result = x + 1;@typescript-eslint/no-unused-vars
Disallow unused variables (TypeScript version).
// bad
const unused = 1;
// good
const used = 1;
console.log(used);@typescript-eslint/no-use-before-define
Disallow using variables before they are defined (TypeScript version).
// bad
console.log(x);
const x = 1;
// good
const x = 1;
console.log(x);@typescript-eslint/no-useless-constructor
Disallow unnecessary constructors (TypeScript version).
// bad
class Foo {
constructor() { super(); }
}
// good
class Foo extends Bar {}@typescript-eslint/no-useless-empty-export
Disallow empty exports that do not change anything in a module file.
// bad
export const x = 1;
export {};
// good
export const x = 1;@typescript-eslint/no-useless-template-literals
Disallow unnecessary template literals.
// bad
const x = `hello`;
// good
const x = 'hello';@typescript-eslint/no-var-requires
Disallow require statements except in import statements.
// bad
const fs = require('fs');
// good
import fs from 'fs';@typescript-eslint/no-wrapper-object-types
Disallow String, Number, Boolean as types.
// bad
const fn = (x: String) => {};
// good
const fn = (x: string) => {};@typescript-eslint/non-nullable-type-assertion-style
Enforce non-null assertions over explicit type casts when possible.
// bad
const x = value as string;
// good
const x = value!;@typescript-eslint/only-throw-error
Require throwing Error objects only (TypeScript version).
// bad
throw 'error';
// good
throw new Error('error');@typescript-eslint/parameter-properties
Require or disallow parameter properties in class constructors.
// bad
class Foo {
x: number;
constructor(x: number) { this.x = x; }
}
// good
class Foo {
constructor(public x: number) {}
}@typescript-eslint/prefer-as-const
Enforce the use of as const over literal types.
// bad
const x: 'hello' = 'hello';
// good
const x = 'hello' as const;@typescript-eslint/prefer-enum-initializers
Require initializers for each enum member.
// bad
enum Status { Active, Inactive }
// good
enum Status { Active = 0, Inactive = 1 }@typescript-eslint/prefer-find
Enforce using Array.find over Array.filter + index access.
// bad
const item = items.filter((i) => i.id === 1)[0];
// good
const item = items.find((i) => i.id === 1);@typescript-eslint/prefer-for-of
Enforce using for...of loops over standard for loops when the index is unused.
// bad
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
// good
for (const item of arr) {
console.log(item);
}@typescript-eslint/prefer-function-type
Enforce using function types instead of interfaces with call signatures.
// bad
interface Fn { (): void; }
// good
type Fn = () => void;@typescript-eslint/prefer-includes
Enforce using includes() over indexOf() !== -1.
// bad
if (arr.indexOf(item) !== -1) {}
// good
if (arr.includes(item)) {}@typescript-eslint/prefer-literal-enum-member
Enforce that enum members are literal values.
// bad
enum E { A = computed() }
// good
enum E { A = 'a' }@typescript-eslint/prefer-namespace-keyword
Enforce using namespace keyword over module keyword.
// bad
module Foo {}
// good
namespace Foo {}@typescript-eslint/prefer-nullish-coalescing
Enforce using ?? instead of || for nullable values.
// bad
const x = value || 'default';
// good
const x = value ?? 'default';@typescript-eslint/prefer-optional-chain
Enforce using optional chaining over nested conditions.
// bad
const x = foo && foo.bar && foo.bar.baz;
// good
const x = foo?.bar?.baz;@typescript-eslint/prefer-readonly
Enforce that class members not modified after construction are marked readonly.
// bad
class Foo { private x = 1; }
// good
class Foo { private readonly x = 1; }@typescript-eslint/prefer-reduce-type-parameter
Enforce using type parameter over casting in Array.reduce.
// bad
const sum = arr.reduce((a, b) => a + b, 0 as number);
// good
const sum = arr.reduce<number>((a, b) => a + b, 0);@typescript-eslint/prefer-regexp-exec
Enforce using RegExp.exec() over String.match() when no global flag.
// bad
'hello'.match(/ell/);
// good
/ell/.exec('hello');@typescript-eslint/prefer-return-this-type
Enforce that this is used as the return type when a class method returns this.
// bad
class Builder {
set(): Builder { return this; }
}
// good
class Builder {
set(): this { return this; }
}@typescript-eslint/prefer-string-starts-ends-with
Enforce using startsWith() and endsWith() over equivalent string methods.
// bad
if (str.indexOf('abc') === 0) {}
// good
if (str.startsWith('abc')) {}@typescript-eslint/prefer-ts-expect-error
Enforce using @ts-expect-error over @ts-ignore.
// bad
// @ts-ignore
const x: number = 'hello';
// good
// @ts-expect-error -- testing invalid input
const x: number = 'hello';@typescript-eslint/promise-function-async
Require functions that return Promises to be marked async.
// bad
function fn(): Promise<void> { return doWork(); }
// good
async function fn(): Promise<void> { return doWork(); }@typescript-eslint/require-array-sort-compare
Require a compare function for Array.sort().
// bad
items.sort();
// good
items.sort((a, b) => a - b);@typescript-eslint/restrict-plus-operands
Require both operands of + to be the same type.
// bad
const x = 'count: ' + 5;
// good
const x = `count: ${5}`;@typescript-eslint/restrict-template-expressions
Enforce template literal expressions to be of string type.
// bad
const msg = `value: ${obj}`;
// good
const msg = `value: ${String(obj)}`;@typescript-eslint/return-await
Enforce returning awaited values in specific contexts.
// bad
async function fn() {
return promise;
}
// good
async function fn() {
return await promise;
}@typescript-eslint/switch-exhaustiveness-check
Require switch statements over unions to be exhaustive.
// bad
type T = 'a' | 'b';
switch (x as T) {
case 'a': break;
}
// good
type T = 'a' | 'b';
switch (x as T) {
case 'a': break;
case 'b': break;
}@typescript-eslint/triple-slash-reference
Disallow triple-slash reference directives.
// bad
/// <reference path="foo" />
// good
import foo from 'foo';@typescript-eslint/typedef
Require type annotations in specific places.
// bad
const fn = (x) => x;
// good
const fn = (x: number): number => x;@typescript-eslint/unbound-method
Enforce that unbound methods are called with their expected scope.
// bad
const fn = obj.method;
fn();
// good
const fn = obj.method.bind(obj);
fn();@typescript-eslint/unified-signatures
Enforce unified signatures for overloads that could be unified.
// bad
function fn(x: string): void;
function fn(x: number): void;
// good
function fn(x: string | number): void;React Rules
react/button-has-type
Require explicit type attribute on <button> elements.
// bad
<button>Click</button>
// good
<button type="button">Click</button>react/checked-requires-onchange-or-readonly
Require onChange or readOnly when checked is used.
// bad
<input type="checkbox" checked={true} />
// good
<input type="checkbox" checked={true} onChange={handleChange} />react/default-props-match-prop-types
Require all defaultProps to have a corresponding non-required prop type.
// bad
type Props = { name: string };
const Comp = ({ name }: Props) => <div>{name}</div>;
Comp.defaultProps = { age: 25 };
// good
type Props = { name: string; age?: number };
const Comp = ({ name, age }: Props) => <div>{name}</div>;
Comp.defaultProps = { age: 25 };react/exhaustive-deps
Verify the list of dependencies for Hooks like useEffect and useCallback.
// bad
useEffect(() => { fetchData(id); }, []);
// good
useEffect(() => { fetchData(id); }, [id]);react/forward-ref-uses-ref
Require forwardRef components to use the ref parameter.
// bad
const Comp = forwardRef((props, ref) => <div />);
// good
const Comp = forwardRef((props, ref) => <div ref={ref} />);react/iframe-missing-sandbox
Require sandbox attribute on <iframe> elements.
// bad
<iframe src="https://example.com" />
// good
<iframe src="https://example.com" sandbox="allow-scripts" />react/jsx-boolean-value
Enforce boolean attributes notation in JSX.
// bad
<Component disabled={true} />
// good
<Component disabled />react/jsx-curly-brace-presence
Enforce curly braces or disallow unnecessary curly braces in JSX.
// bad
<Component name={'hello'} />
// good
<Component name="hello" />react/jsx-filename-extension
Restrict file extensions that may contain JSX.
// bad
// Button.js with JSX content
// good
// Button.tsx with JSX contentreact/jsx-fragments
Enforce shorthand Fragment syntax.
// bad
<React.Fragment><Child /></React.Fragment>
// good
<><Child /></>react/jsx-key
Require key props on elements in iterators.
// bad
items.map((item) => <li>{item}</li>);
// good
items.map((item) => <li key={item.id}>{item.name}</li>);react/jsx-max-depth
Enforce maximum JSX depth.
// bad
<A><B><C><D><E><F /></E></D></C></B></A>
// good
<A><Content /></A>react/jsx-no-bind
Disallow .bind() or arrow functions in JSX props.
// bad
<Button onClick={() => handleClick(id)} />
// good
const handleButtonClick = useCallback(() => handleClick(id), [id]);
<Button onClick={handleButtonClick} />react/jsx-no-comment-textnodes
Disallow comments as text nodes in JSX.
// bad
<div>// comment</div>
// good
<div>{/* comment */}</div>react/jsx-no-constructed-context-values
Prevent non-stable values from being used as context value.
// bad
<Ctx.Provider value={{ user, setUser }}>
// good
const value = useMemo(() => ({ user, setUser }), [user]);
<Ctx.Provider value={value}>react/jsx-no-duplicate-props
Disallow duplicate props in JSX.
// bad
<Component name="a" name="b" />
// good
<Component name="a" title="b" />react/jsx-no-leaked-render
Prevent problematic leaked values from being rendered.
// bad
{count && <Items count={count} />}
// good
{count > 0 && <Items count={count} />}react/jsx-no-script-url
Disallow javascript: URLs in JSX.
// bad
<a href="javascript:void(0)">Click</a>
// good
<a href="#" onClick={handleClick}>Click</a>react/jsx-no-target-blank
Require rel="noreferrer" with target="_blank".
// bad
<a href={url} target="_blank">Link</a>
// good
<a href={url} target="_blank" rel="noreferrer">Link</a>react/jsx-no-undef
Disallow undeclared variables in JSX.
// bad
const App = () => <MissingComponent />;
// good
import { MyComponent } from './my-component';
const App = () => <MyComponent />;react/jsx-no-useless-fragment
Disallow unnecessary fragments.
// bad
<>{child}</>
// good
{child}react/jsx-props-no-spread-key
Disallow key being spread into JSX.
// bad
const props = { key: 'id', name: 'foo' };
<Component {...props} />
// good
<Component key="id" name="foo" />react/jsx-sort-props
Enforce alphabetical prop sorting. Handled by perfectionist.
react/jsx-uses-vars
Mark variables used in JSX as used.
// good
import { Component } from './component';
const App = () => <Component />;react/no-access-state-in-setstate
Disallow accessing this.state inside setState.
// bad
this.setState({ count: this.state.count + 1 });
// good
this.setState((prev) => ({ count: prev.count + 1 }));react/no-array-index-key
Disallow using array index as key.
// bad
items.map((item, i) => <li key={i}>{item}</li>);
// good
items.map((item) => <li key={item.id}>{item.name}</li>);react/no-children-prop
Disallow passing children as props.
// bad
<Component children={<Child />} />
// good
<Component><Child /></Component>react/no-danger
Disallow dangerouslySetInnerHTML.
// bad
<div dangerouslySetInnerHTML={{ __html: html }} />
// good
<div>{sanitizedContent}</div>react/no-danger-with-children
Disallow dangerouslySetInnerHTML alongside children.
// bad
<div dangerouslySetInnerHTML={{ __html: 'hi' }}>Child</div>
// good
<div dangerouslySetInnerHTML={{ __html: 'hi' }} />react/no-deprecated
Disallow deprecated React methods.
// bad
ReactDOM.render(<App />, el);
// good
createRoot(el).render(<App />);react/no-did-mount-set-state
Disallow setState in componentDidMount.
// bad
componentDidMount() { this.setState({ loaded: true }); }
// good
// Use useEffect with state initialization insteadreact/no-did-update-set-state
Disallow setState in componentDidUpdate.
// bad
componentDidUpdate() { this.setState({ updated: true }); }
// good
// Derive state from props or use getDerivedStateFromPropsreact/no-direct-mutation-state
Disallow direct mutation of this.state.
// bad
this.state.count = 1;
// good
this.setState({ count: 1 });react/no-find-dom-node
Disallow ReactDOM.findDOMNode.
// bad
ReactDOM.findDOMNode(this);
// good
const ref = useRef<HTMLDivElement>(null);react/no-is-mounted
Disallow isMounted.
// bad
if (this.isMounted()) { this.setState({}); }
// good
// Use an AbortController or cleanup in useEffectreact/no-multi-comp
Enforce a single component per file.
// bad
const A = () => <div />;
const B = () => <div />;
// good
// a.tsx: const A = () => <div />;react/no-namespace
Disallow React namespace syntax (e.g., <Foo:Bar />).
// bad
<Foo:Bar />
// good
<FooBar />react/no-redundant-should-component-update
Disallow shouldComponentUpdate when extending PureComponent.
// bad
class Foo extends PureComponent {
shouldComponentUpdate() { return true; }
}
// good
class Foo extends PureComponent {}react/no-render-return-value
Disallow using the return value of ReactDOM.render.
// bad
const app = ReactDOM.render(<App />, el);
// good
ReactDOM.render(<App />, el);react/no-string-refs
Disallow string refs.
// bad
<div ref="myDiv" />
// good
<div ref={myRef} />react/no-this-in-sfc
Disallow this in stateless function components.
// bad
const Comp = () => <div>{this.props.name}</div>;
// good
const Comp = ({ name }: Props) => <div>{name}</div>;react/no-unescaped-entities
Disallow unescaped HTML entities in JSX.
// bad
<div>Don't use "quotes"</div>
// good
<div>Don't use "quotes"</div>react/no-unknown-property
Disallow unknown DOM properties.
// bad
<div class="foo" />
// good
<div className="foo" />react/no-unsafe
Disallow usage of unsafe lifecycle methods.
// bad
UNSAFE_componentWillMount() {}
// good
componentDidMount() {}react/no-unstable-nested-components
Disallow creating unstable components inside components.
// bad
const Parent = () => {
const Child = () => <div />;
return <Child />;
};
// good
const Child = () => <div />;
const Parent = () => <Child />;react/no-unused-class-component-methods
Disallow unused methods in class components.
// bad
class Foo extends Component {
unusedMethod() {}
render() { return <div />; }
}
// good
class Foo extends Component {
render() { return <div />; }
}react/no-unused-prop-types
Disallow unused prop types.
// bad
type Props = { name: string; age: number };
const Comp = ({ name }: Props) => <div>{name}</div>;
// good
type Props = { name: string };
const Comp = ({ name }: Props) => <div>{name}</div>;react/no-unused-state
Disallow unused state fields.
// bad
state = { count: 0, unused: '' };
render() { return <div>{this.state.count}</div>; }
// good
state = { count: 0 };
render() { return <div>{this.state.count}</div>; }react/no-will-update-set-state
Disallow setState in componentWillUpdate.
// bad
componentWillUpdate() { this.setState({}); }
// good
// Use getDerivedStateFromProps or componentDidUpdatereact/prefer-es6-class
Enforce ES6 class syntax for React components.
// bad
const Comp = createReactClass({ render() {} });
// good
class Comp extends Component { render() {} }react/prefer-stateless-function
Encourage stateless functional components.
// bad
class Foo extends Component {
render() { return <div>{this.props.name}</div>; }
}
// good
const Foo = ({ name }: Props) => <div>{name}</div>;react/require-render-return
Require render method to return a value.
// bad
class Foo extends Component {
render() { <div />; }
}
// good
class Foo extends Component {
render() { return <div />; }
}react/rules-of-hooks
Enforce Rules of Hooks.
// bad
if (condition) { useState(0); }
// good
const [count, setCount] = useState(0);react/self-closing-comp
Require self-closing tags when children are not needed.
// bad
<Component></Component>
// good
<Component />react/style-prop-object
Enforce that the style prop value is an object.
// bad
<div style="color: red" />
// good
<div style={{ color: 'red' }} />react/void-dom-elements-no-children
Disallow children on void DOM elements.
// bad
<br>children</br>
// good
<br />React Compiler Rules
react-hooks-js/component-hook-factories
Enforce that component hook factory functions follow compiler rules.
// bad
const useCustom = createHook(() => {
let x = 0;
x = 1;
return x;
});
// good
const useCustom = createHook(() => {
const [x, setX] = useState(0);
return x;
});react-hooks-js/config
Validate React Compiler configuration.
// bad
// Invalid compiler options
// good
// Valid compiler configuration in babel/next configreact-hooks-js/error-boundaries
Enforce correct error boundary patterns for the compiler.
// bad
class ErrorBoundary extends Component {
state = {};
}
// good
class ErrorBoundary extends Component {
state = { hasError: false };
static getDerivedStateFromError() { return { hasError: true }; }
}react-hooks-js/gating
Enforce gating patterns are compatible with the compiler.
// bad
if (__DEV__) { useDebugHook(); }
// good
useDebugHook(__DEV__);react-hooks-js/globals
Enforce that global references are compatible with the compiler.
// bad
function Comp() { return <div>{window.x}</div>; }
// good
function Comp() {
const x = useSyncExternalStore(subscribe, getSnapshot);
return <div>{x}</div>;
}react-hooks-js/immutability
Enforce immutable data patterns required by the compiler.
// bad
function Comp({ items }) {
items.sort();
return <List items={items} />;
}
// good
function Comp({ items }) {
const sorted = [...items].sort();
return <List items={sorted} />;
}react-hooks-js/incompatible-library
Flag usage of libraries incompatible with the React Compiler.
// bad
import { observer } from 'mobx-react';
// good
// Use compiler-compatible state managementreact-hooks-js/preserve-manual-memoization
Preserve existing useMemo/useCallback usage for the compiler.
// bad
const value = useMemo(() => compute(a), []);
// good
const value = useMemo(() => compute(a), [a]);react-hooks-js/purity
Enforce that components and hooks are pure functions.
// bad
let count = 0;
function Comp() {
count += 1;
return <div>{count}</div>;
}
// good
function Comp() {
const [count, setCount] = useState(0);
return <div>{count}</div>;
}react-hooks-js/refs
Enforce correct ref patterns for the compiler.
// bad
function Comp() {
const ref = useRef(null);
return <div>{ref.current}</div>;
}
// good
function Comp() {
const ref = useRef<HTMLDivElement>(null);
return <div ref={ref} />;
}react-hooks-js/set-state-in-effect
Enforce correct setState usage inside effects.
// bad
useEffect(() => {
setCount(count + 1);
}, [count]);
// good
useEffect(() => {
setCount((prev) => prev + 1);
}, []);react-hooks-js/set-state-in-render
Disallow setState during render.
// bad
function Comp() {
const [x, setX] = useState(0);
setX(1);
return <div />;
}
// good
function Comp() {
const [x, setX] = useState(0);
useEffect(() => { setX(1); }, []);
return <div />;
}react-hooks-js/static-components
Enforce that static components are defined outside of render.
// bad
function Parent() {
const Header = () => <h1>Title</h1>;
return <Header />;
}
// good
const Header = () => <h1>Title</h1>;
function Parent() { return <Header />; }react-hooks-js/unsupported-syntax
Flag syntax patterns not yet supported by the React Compiler.
// bad
function Comp() {
with (obj) { return <div />; }
}
// good
function Comp() { return <div>{obj.value}</div>; }react-hooks-js/use-memo
Enforce correct useMemo usage for the compiler.
// bad
const value = useMemo(() => expensive(a, b), [a]);
// good
const value = useMemo(() => expens