跪拜 Guibai
← Back to the summary

ESLint Catches the Bugs Code Review Misses

From "code that just runs" to "code that runs and is elegant," the gap is bridged by ESLint.

One-Sentence Answer

ESLint is a static analysis tool for JavaScript/TypeScript code—it doesn't run your code, but reads your code, finds syntax errors, bad smells, and inconsistent styles, then tells you where to change and how.


Why Do You Need ESLint?

1. Catch Low-Level Errors Early

// What do you think is wrong with this code?
if (isAdmin = true) {
  deleteUserAccount();
}

Did you write = instead of ==? No, an assignment was placed inside an if condition. This code runs without a syntax error, but it will delete the user account when you're not paying attention. ESLint's no-cond-assign rule flags it the moment you type it.

Similar issues include:

These bugs are often hard to track down at runtime, but static analysis can find them in 0.1 seconds.

2. Unify Team Style, Eliminate Pointless Code Review Debates

"Should curly braces go on the same line or a new line?" "Tabs or spaces for indentation?" "Semicolons or not?"

These questions don't belong in Code Review. They have no right or wrong answer, but when a team isn't unified, reading code creates cognitive load. ESLint hardens these style decisions into rules, automatically checking before code submission and reporting errors for non-compliance.

// ESLint makes the team's code look the same
const foo = () => {
  if (condition) {
    doSomething();
  }
};

3. Enforce Best Practices

JavaScript has many patterns that "work but aren't good." ESLint includes a large set of best-practice rules:

Rule Prevents What
no-var Encourages let/const over var, avoiding hoisting traps
prefer-const Variables never reassigned must use const
no-eval Bans eval(), preventing injection attacks
no-implicit-globals Prevents accidental global variable creation
prefer-arrow-callback Encourages arrow functions, reducing this binding issues
no-duplicate-case Prevents duplicate case clauses in switch

4. Deep Editor Integration, Real-Time Feedback

Editors like VS Code and WebStorm support ESLint plugins. As you code, the editor can:

This "correct as you err" experience is far more efficient than waiting for CI to find problems.


How ESLint Works

ESLint's core process can be summarized in three steps:

Parse → Traverse → Report

  1. Parse: ESLint parses your source code into an AST (Abstract Syntax Tree). JavaScript uses the Espree parser; TypeScript requires @typescript-eslint/parser.
  2. Traverse: ESLint walks every node of the AST, checking for matching rules at each node.
  3. Report: When a rule matches, it outputs diagnostic information at the level configured (off / warn / error).

Plugins provide rules, and configuration decides which rules are enabled and at what level. This is ESLint's "plugins + configuration" design philosophy.


Quick Start

Installation

npm install -D eslint

Initialize Configuration

npx eslint --init

ESLint will ask a few questions (project type, framework, TypeScript usage, etc.) and then generate .eslintrc.js:

// .eslintrc.js — Legacy config format (eslintrc)
module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: 'eslint:recommended',
  parserOptions: {
    ecmaVersion: 2021,
    sourceType: 'module',
  },
  rules: {
    'no-unused-vars': 'warn',
    'no-console': 'warn',
    'eqeqeq': 'error',
    'prefer-const': 'error',
  },
};

New Config Format (Flat Config)

ESLint 9+ defaults to the flat configuration eslint.config.js:

// eslint.config.js
import js from '@eslint/js';

export default [
  js.configs.recommended,
  {
    rules: {
      'no-unused-vars': 'warn',
      'no-console': 'warn',
      'eqeqeq': 'error',
    },
  },
];

Flat config replaces inheritance chains with arrays, making it more intuitive and easier to understand where each rule comes from.

Running

# Check all files
npx eslint .

# Check and auto-fix
npx eslint . --fix

# Check specific files only
npx eslint src/**/*.js

With npm scripts

{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
}

Common Rules Quick Reference

Error Detection

rules: {
  'no-unused-vars': 'error',      // Declared but unused variables
  'no-undef': 'error',            // Using undefined variables
  'no-unreachable': 'error',      // Unreachable code after return
  'no-cond-assign': 'error',      // Assignment in conditional statements
  'no-debugger': 'error',         // debugger statements
}

Style Conventions

rules: {
  'indent': ['error', 2],              // Uniform 2-space indentation
  'quotes': ['error', 'single'],       // Uniform single quotes
  'semi': ['error', 'always'],         // Enforce semicolons
  'no-trailing-spaces': 'error',       // No trailing spaces
  'eol-last': 'error',                 // Newline at end of file
}

Best Practices

rules: {
  'eqeqeq': 'error',              // Must use === not ==
  'no-eval': 'error',             // Ban eval
  'no-var': 'error',              // Ban var
  'prefer-const': 'error',        // Prefer const
  'no-multiple-empty-lines': ['error', { max: 2 }],
}

Suggestion: Leave style rules to Prettier, and let ESLint focus on code quality and best practices. Each tool does its own job. More on this later.


Relationship with Prettier

Many people confuse ESLint and Prettier. Simply put:

ESLint Prettier
Focus Code quality + code style Pure code formatting
Typical Issues Unused variables, == vs ===, unreachable code Indentation, quotes, line breaks, line width
Can fix logic? Can find issues, some auto-fixable No, only changes formatting, not logic
Configurable rules? Yes, hundreds Almost none, only a few options

Best Practice: Use both together.

npm install -D prettier eslint-config-prettier
// .eslintrc.js
module.exports = {
  extends: [
    'eslint:recommended',
    'prettier',  // Place last, turns off conflicting format rules
  ],
};

How to Configure for TypeScript Projects?

TypeScript projects need an additional parser and plugin:

npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
// eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';

export default tseslint.config(
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    rules: {
      '@typescript-eslint/no-unused-vars': 'warn',
      '@typescript-eslint/no-explicit-any': 'warn',
    },
  },
);

@typescript-eslint can check type-level errors, such as:


Automate with Git Hooks

The ideal state: code is automatically checked before committing, and substandard code never enters the repository.

Using lint-staged + husky

npm install -D husky lint-staged
npx husky init
// package.json
{
  "scripts": {
    "prepare": "husky"
  },
  "lint-staged": {
    "*.{js,ts,jsx,tsx}": "eslint --fix"
  }
}
echo "npx lint-staged" > .husky/pre-commit

Now, on every git commit, ESLint automatically checks the staged files and blocks the commit if there are issues. Only new/modified files are checked, not a full scan, so it's fast.


Common Configuration Presets

Rather than configuring from scratch, stand on the shoulders of giants. The community provides many mature config presets:

Preset Characteristics
eslint:recommended ESLint official recommendation, covers the most common error detection
eslint-config-airbnb Airbnb's strict style guide, once the community standard
eslint-config-standard Standard style, no semicolons, no redundant config
eslint-config-next Next.js official config, includes React + a11y rules
eslint-config-react-app CRA built-in config
eslint-config-prettier Turns off rules conflicting with Prettier
// Combined usage
export default [
  js.configs.recommended,
  ...reactHooks.configs.recommended,
  ...reactRefresh.configs.vite,
  prettierConfig,  // Place last
];

Summary

The core problem ESLint solves: Expose errors early, keep style consistent, and make best practices a habit.

Without ESLint With ESLint
Bugs exposed only at runtime Found while coding
Code Review debates semicolons Code Review focuses on logic
Everyone's code style differs Team code looks like one person wrote it
Newcomers don't know best practices Rules themselves are documentation and teaching

If you haven't used ESLint in your project yet, install it now:

npm install -D eslint
npx eslint --init

Your codebase will thank you.