Skip to main content
The best-practices rule file enforces safe, predictable JavaScript patterns. These rules catch common bugs, discourage error-prone idioms, and guide you toward modern language features. Source: eslint-config-airbnb-base/rules/best-practices

Equality and type safety

Severity: errorRequires strict equality operators (=== and !==) everywhere. The null case is excluded to allow value == null as a shorthand for value === null || value === undefined.
// Bad
if (x == 1) { }

// Good
if (x === 1) { }
if (value == null) { } // allowed
Severity: errorComparing a value to itself is almost always a typo or logic error.
// Bad
if (x === x) { }

Function and class patterns

Severity: errorReassigning function parameters can cause unexpected behavior, especially with arguments aliasing. The rule also disallows modifying parameter properties, with specific exceptions for common patterns.Allowed property modifications:
  • acc / accumulator — reduce accumulators
  • e — event return values
  • ctx / context — Koa routing
  • req / request — Express requests
  • res / response — Express responses
  • $scope — Angular 1 scopes
  • staticContext — ReactRouter context
// Bad
function double(n) {
  n = n * 2; // reassignment
  return n;
}

// Good
function double(n) {
  const result = n * 2;
  return result;
}
Severity: errorClass methods that do not reference this should be static methods or standalone functions.
Severity: errorConstructors must not return a value. Returning a primitive is silently ignored; returning an object replaces the newly created instance, which is almost always unintentional.
Severity: error (max: 1)Each file should export a single class to keep module responsibilities clear.

Dangerous and deprecated features

Severity: erroreval() executes arbitrary code, creates security vulnerabilities, and prevents engine optimizations.
Severity: errorPrevents passing strings to setTimeout, setInterval, and execScript, which behave like eval.
// Bad
setTimeout('doSomething()', 1000);

// Good
setTimeout(doSomething, 1000);
Severity: errornew Function(string) is essentially eval and carries the same risks.
Severity: error__proto__ is a deprecated way to access an object’s prototype. Use Object.getPrototypeOf() instead.
Severity: errorAdding properties to built-in prototypes like Array.prototype can break other code unexpectedly.
Severity: errorjavascript: URLs evaluate code in the page context, creating a cross-site scripting vector.

Code structure

Severity: errorA function must either always return a value or never return a value (other than undefined). Inconsistent returns make code harder to reason about.
Severity: errorSwitch statements must include a default clause. Use a // no default comment to explicitly opt out.
switch (action.type) {
  case 'INCREMENT':
    return state + 1;
  default:
    return state;
}
Severity: errorfor...in loops iterate over the full prototype chain. An if check (hasOwnProperty) prevents processing inherited properties.
// Bad
for (const key in obj) {
  doSomething(key);
}

// Good
for (const key in obj) {
  if (Object.prototype.hasOwnProperty.call(obj, key)) {
    doSomething(key);
  }
}
Severity: errorWhen a branch ends with a return, an else block is unnecessary and adds indentation.
// Bad
function foo(x) {
  if (x > 0) {
    return x;
  } else {
    return -x;
  }
}

// Good
function foo(x) {
  if (x > 0) {
    return x;
  }
  return -x;
}
Severity: errorBlock statements outside of control flow are a no-op in non-strict mode and serve no purpose.
Severity: errorBecause var declarations are hoisted, declaring them at the top of their scope makes the hoisting behavior explicit.

Expressions and statements

Severity: errorAn expression statement that has no side effect (e.g., a && b without using the result) is most likely a bug. Short-circuit evaluation, ternaries, and tagged template literals are not allowed as statements.
// Bad — no side effect
a && b;
a ? b : c;

// Good
a && b();
const result = a ? b : c;
Severity: errorThe comma operator evaluates both operands and returns the value of the last one. This is rarely intentional and can hide bugs.
Severity: errorOnly Error objects (or subclasses) should be thrown so that consumers can rely on stack traces and .message.
// Bad
throw 'Something went wrong';
throw 404;

// Good
throw new Error('Something went wrong');
Severity: errorAssignment inside a return statement is almost always a typo for ===.
Severity: errorreturn await promise in an async function is redundant because the outer function already awaits the returned promise. Removing await avoids an unnecessary microtask tick and simplifies stack traces.

Restricted properties

The config bans several legacy or unsafe property accesses:
AccessReplacement
arguments.calleeDeprecated; use named functions
global.isFinite / window.isFiniteNumber.isFinite
global.isNaN / window.isNaNNumber.isNaN
obj.__defineGetter__Object.defineProperty
obj.__defineSetter__Object.defineProperty
Math.pow** exponentiation operator

Async patterns

Severity: errorPromises should be rejected with Error instances so that consumers have access to stack traces. Empty rejections (Promise.reject()) are allowed.
// Bad
Promise.reject('network error');

// Good
Promise.reject(new Error('network error'));

Build docs developers (and LLMs) love