npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

oxlint-config-awesomeness

v1.2.0

Published

Oxlint config with sensible defaults.

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 at error. 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.log or test.only are errors. Missing throw, 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:

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 comment

class-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 lines

max-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 instead

no-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 later

no-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 content

react/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 instead

react/no-did-update-set-state

Disallow setState in componentDidUpdate.

// bad
componentDidUpdate() { this.setState({ updated: true }); }

// good
// Derive state from props or use getDerivedStateFromProps

react/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 useEffect

react/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&apos;t use &quot;quotes&quot;</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 componentDidUpdate

react/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 config

react-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 management

react-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