ESLint + Prettier の設定ベストプラクティス(React / TypeScript)

概要

React プロジェクトで ESLint と Prettier を併用すると、「保存のたびに整形が競合して怒られる」「どちらが何を担当しているのか曖昧なまま設定ファイルが肥大化する」という問題が起きがちです。

この記事では、ESLint はコードの品質(バグの芽・アンチパターン)を、Prettier は見た目(整形)を担当するという役割分担を軸に、両者を競合させずに共存させる設定をハンズオンで組み立てます。ESLint v9 の Flat Config(eslint.config.js)を前提にします。

環境

  • Node.js 20 以上
  • React 18 / 19
  • TypeScript 5 系
  • ESLint 9 系(Flat Config)
  • Prettier 3 系

そもそもの役割分担

最初に押さえるべきは、ESLint と Prettier の責務を重ねないという原則です。

ツール 担当 例
ESLint コード品質・ロジック 未使用変数、useEffect の依存漏れ、== の誤用
Prettier 整形(フォーマット) インデント、クォート、セミコロン、行幅

かつては ESLint 側にもインデントやクォートを整える「スタイル系ルール」がありましたが、これを有効にすると Prettier と衝突します。そこで 整形は Prettier に一任し、ESLint 側の整形ルールは無効化するのが定石です。この無効化を担うのが eslint-config-prettier です。

インストール

pnpm add -D eslint @eslint/js typescript-eslint \
  eslint-plugin-react eslint-plugin-react-hooks \
  eslint-config-prettier prettier
  • @eslint/js — ESLint 公式の推奨ルールセット
  • typescript-eslint — TS 用パーサ+ルール
  • eslint-plugin-react / eslint-plugin-react-hooks — React 固有ルール
  • eslint-config-prettier — Prettier と衝突する整形ルールをまとめて無効化
  • prettier — 整形本体

Prettier の設定

.prettierrc.json を用意します。設定は「チームで揉めそうな項目だけ」明示し、あとはデフォルトに従うのが保守的で楽です。

{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "tabWidth": 2,
  "arrowParens": "always"
}

整形対象外にしたいものは .prettierignore に書きます。

dist
build
coverage
pnpm-lock.yaml

ESLint Flat Config を組み立てる

eslint.config.js を作成します。配列は上から順に適用され、後の要素が前の要素を上書きするのがポイントです。そのため eslint-config-prettier は必ず最後に置きます。

// eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import prettier from 'eslint-config-prettier';

export default tseslint.config(
  { ignores: ['dist', 'build', 'coverage'] },

  js.configs.recommended,
  ...tseslint.configs.recommended,

  {
    files: ['**/*.{ts,tsx}'],
    plugins: {
      react,
      'react-hooks': reactHooks,
    },
    languageOptions: {
      parserOptions: {
        ecmaFeatures: { jsx: true },
      },
    },
    settings: {
      react: { version: 'detect' },
    },
    rules: {
      ...react.configs.recommended.rules,
      ...reactHooks.configs.recommended.rules,
      'react/react-in-jsx-scope': 'off', // React 17+ の新 JSX Transform
      'react/prop-types': 'off',         // TypeScript で型を付けるので不要
    },
  },

  {
    rules: {
      '@typescript-eslint/no-unused-vars': [
        'warn',
        { argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
      ],
    },
  },

  prettier, // ★必ず最後★
);

スクリプトを整える

package.json に、lint と format を分けて登録します。

{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "format": "prettier --write .",
    "format:check": "prettier --check ."
  }
}

CI では検査だけしたいので lint と format:check を、ローカルでは lint:fix と format を使う、という切り分けになります。

エディタ連携(VS Code)

.vscode/settings.json に置くとチーム全体で揃います。

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  }
}

確認方法

  1. わざと整形が崩れた TSX を書く
  2. pnpm lint を実行 → 整形の乱れでは怒られないことを確認
  3. pnpm format を実行 → 整形が直ることを確認
  4. 競合チェックを実行:
npx eslint-config-prettier eslint.config.js

No rules that are unnecessary or conflict with Prettier were found. と出れば正常です。

注意点

  • eslint-config-prettier は最後に置く。順番を間違えると整形ルールが復活します。
  • eslint-plugin-prettier は原則不要。整形ズレが lint エラーになり煩雑・低速になります。
  • react/react-in-jsx-scope は React 17 以降オフでよい。有効のままだと誤検知します。
  • ルールを盛りすぎない。recommended +数個で始め、摩擦の出た項目だけ追加します。

まとめ

  • ESLint = 品質、Prettier = 整形、と責務を重ねないのが出発点
  • 競合は eslint-config-prettier を Flat Config の最後に置くだけで解消
  • eslint-plugin-prettier は使わず、lint と format を別コマンドで回す
  • 迷ったら recommended から始め、摩擦の出た箇所だけ足す

この分担を最初に決めておくと、プロジェクトが大きくなっても設定ファイルが破綻しにくくなります。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。