ESLint + Prettier + TypeScript が競合しない設定術

概要

ESLint・Prettier・TypeScript を同じプロジェクトに入れると、「保存のたびに整形が暴れる」「npm run lint と npm run format が逆方向の修正を出す」「eslint --fix が延々と差分を生む」といった競合が起きます。

本記事は、この競合の原因を切り分け、ESLint の Flat Config(eslint.config.js)で競合しない構成を作る手順をまとめたトラブルシュート記事です。結論は次の3点です。

  1. 整形は Prettier、コード品質は ESLint と責務を分ける
  2. ESLint の整形系ルールを eslint-config-prettier で無効化する
  3. eslint-plugin-prettier(ESLint から Prettier を回す)は原則やめる

> なお ESLint は v10.0.0(2026-02)で従来の .eslintrc 設定システムが完全に削除されました。.eslintrc.* / .eslintignore や --no-eslintrc などは v10 では読まれず、設定は Flat Config のみが正となります。本記事も Flat Config を正として扱い、.eslintrc は v9 以前を使っている場合の参考に留めます。

環境

  • Node.js 24.x(LTS)/ TypeScript 7.x
  • ESLint 10.x(Flat Config)/ typescript-eslint 8.x
  • Prettier 3.x / eslint-config-prettier 10.x

発生した問題

典型的な症状は3つです。

  1. 整形の往復: 保存のたびに ESLint の --fix と Prettier の format が別々に走り、インデントやクォートが交互に書き換わる。
  2. lint と format が逆: ESLint は「セミコロンを消せ」、Prettier は「セミコロンを付けろ」。どちらを正としても片方が怒る。
  3. eslint --fix が遅い・差分がうるさい: eslint-plugin-prettier を入れていると、Prettier の整形差分が ESLint エラーとして1行ずつ報告され、lint が重くなる。

原因

根本原因は、「整形」という同じ仕事を ESLint と Prettier の両方が担当していることです。

ESLint には indent / quotes / semi / comma-dangle など整形系ルールがあり、Prettier の整形と衝突します。さらに eslint-plugin-prettier を使うと、ESLint 実行中に Prettier を呼び出して「整形されていない箇所」をすべてエラー化するため、本質的なバグと整形差分がログ上で混ざります。

対応方法

方針は責務分離です。

ツール 担当
Prettier コードの整形(見た目)
ESLint コード品質(バグの芽・アンチパターン)
TypeScript 型チェック
  1. ESLint の整形系ルールを eslint-config-prettier で無効化する
  2. 整形は prettier --write に一本化する
  3. eslint-plugin-prettier は原則使わない

実装例

インストール

npm i -D eslint prettier typescript \
  typescript-eslint eslint-config-prettier

ESLint Flat Config(eslint.config.js)

ESLint v9 以降の標準であり、v10 では唯一の設定方式です。eslintConfigPrettier を配列の最後に置くことで、後勝ちで整形系ルールを無効化できます。

import js from "@eslint/js";
import tseslint from "typescript-eslint";
import eslintConfigPrettier from "eslint-config-prettier";

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    rules: {
      "@typescript-eslint/no-unused-vars": [
        "warn",
        { argsIgnorePattern: "^_" },
      ],
      "no-console": "warn",
    },
  },
  eslintConfigPrettier, // 必ず最後
];

従来の .eslintrc(v9 以前向け・v10 では利用不可)

ESLint v9 以前で .eslintrc を使っている場合は、extends の最後に "prettier" を置くのが鉄則です。ただし v10 では .eslintrc 自体が読まれなくなったため、この形式は使えません。v10 へ上げる場合は npx @eslint/migrate-config .eslintrc.json で Flat Config へ移行してください。

{
  "root": true,
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ]
}

Prettier 設定(.prettierrc.json)

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

npm scripts

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

VSCode(.vscode/settings.json)

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

確認方法

競合ルールの残存チェック

npx eslint-config-prettier eslint.config.js

「No rules that are unnecessary or conflict with Prettier were found.」と出れば、ESLint 側に整形系ルールが残っていない証拠です。残っていればルール名が列挙されます。

整形後に差分が増えないこと

npm run format
npm run lint
git diff --stat   # 整形由来の差分が出ないこと

注意点

  • eslintConfigPrettier は必ず最後に置く。途中に置くと後続設定が整形ルールを復活させ、競合が再発する。
  • eslint-plugin-prettier(ESLint から Prettier 実行)と eslint-config-prettier(整形ルール無効化)は別物。本構成で必須なのは後者だけ。
  • CI は lint と format:check を別ステップにすると、失敗理由が「バグ」か「整形」かで読み分けやすい。

まとめ

  • 競合の原因は「整形を ESLint と Prettier が二重に担当する」こと
  • 整形は Prettier、品質は ESLint、型は TypeScript と責務を分ける
  • eslint-config-prettier を設定の最後に置き、ESLint の整形ルールを無効化する
  • 整形は prettier --write に一本化し、npx eslint-config-prettier で残存競合を確認する

この3点を押さえるだけで、「保存のたびに差分が暴れる」問題はほぼ解消します。

\ 最新情報をチェック /

コメントを残す

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