Tips & Tricks (更新: 2026/6/2)

Claude CodeでESLint Flat Configを実務向けに整える

Claude CodeでESLint Flat Configを導入し、TypeScript/React/Astro、CI、修正依頼まで実務手順で解説。

Claude CodeでESLint Flat Configを実務向けに整える

ESLint設定はClaude Codeに丸投げしない

ESLintはJavaScriptやTypeScriptの静的解析ツールです。静的解析とは、アプリを実行する前にコードを読み取り、バグの温床、危ない書き方、チームで揺れやすい書き方を検出する仕組みです。

ESLint v9以降はFlat Configが標準になり、2026年6月時点の公式ドキュメントでもeslint.config.jseslint.config.mjsに設定を集約する流れが続いています。ただし「Claude CodeにESLint設定を作って」とだけ頼むと、古い.eslintrcの癖、型情報を使わない軽すぎる設定、逆にCIが遅くなる重すぎる設定が混ざりやすいです。

この記事ではMasaが小さなReact管理画面、Astro製コンテンツサイト、既存TypeScriptライブラリで使った型をもとに、Claude Codeへどう依頼し、どの設定を残し、どこをCIで止めるかを整理します。コードはコピペして試せる形にし、最後にClaude Codeへ修正を依頼するテンプレートも載せます。

公式情報はESLintのConfiguration Filestypescript-eslintのTyped Linting、Astroの場合はeslint-plugin-astro User Guideを確認してください。Claude CodeのCLI確認はClaude Code CLI referenceが基準です。

まず入れる依存関係とnpm scripts

最初にClaude Codeへ聞く前に、前提を固定します。ESLint本体、TypeScript連携、React Hooks、アクセシビリティ、import並び替えを入れます。Astroを使う場合だけeslint-plugin-astroも追加します。

npm i -D eslint @eslint/js typescript typescript-eslint globals
npm i -D eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y
npm i -D eslint-plugin-simple-import-sort

# Astroプロジェクトだけ追加
npm i -D eslint-plugin-astro astro-eslint-parser

package.jsonには、ローカル修正用とCI用を分けて入れます。--max-warnings=0は警告もCI失敗にする指定です。最初の導入日は厳しすぎるので、エラー数を見てから有効化しても構いません。

{
  "scripts": {
    "lint": "eslint . --max-warnings=0",
    "lint:fix": "eslint . --fix",
    "lint:debug": "eslint --print-config src/App.tsx > .eslint-debug.json",
    "typecheck": "tsc --noEmit",
    "ci:verify": "npm run lint && npm run typecheck"
  }
}

概念図にすると、Claude Codeへ渡すべき情報は「設定ファイル」だけではありません。検証コマンドまで渡して、修正の終点を明確にします。

package.json scripts
  -> eslint.config.mjs
  -> npm run lint:fix
  -> npm run lint
  -> npm run typecheck
  -> CI gate
  -> Claude Codeに差分レビューを依頼

TypeScript/React向けFlat Config

React + TypeScriptの一般的なアプリなら、次のeslint.config.mjsから始めます。projectService: trueはTypeScriptの型情報を使うための設定です。型情報を使うルールは強力ですが重いので、生成物やビルド出力は必ずignoresに入れます。

import js from "@eslint/js";
import globals from "globals";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import jsxA11y from "eslint-plugin-jsx-a11y";
import simpleImportSort from "eslint-plugin-simple-import-sort";
import tseslint from "typescript-eslint";

export default tseslint.config(
  {
    ignores: [
      "node_modules/",
      "dist/",
      "build/",
      "coverage/",
      ".next/",
      ".astro/",
      "public/",
      "*.min.js"
    ]
  },
  js.configs.recommended,
  ...tseslint.configs.strictTypeChecked,
  ...tseslint.configs.stylisticTypeChecked,
  {
    files: ["**/*.{js,mjs,cjs,ts,tsx}"],
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      globals: {
        ...globals.browser,
        ...globals.node,
        ...globals.es2024
      },
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname
      }
    }
  },
  {
    files: ["**/*.{jsx,tsx}"],
    ...react.configs.flat.recommended,
    settings: {
      react: { version: "detect" }
    },
    rules: {
      ...react.configs.flat.recommended.rules,
      "react/react-in-jsx-scope": "off",
      "react/prop-types": "off"
    }
  },
  {
    files: ["**/*.{jsx,tsx}"],
    plugins: {
      "react-hooks": reactHooks,
      "jsx-a11y": jsxA11y
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      ...jsxA11y.configs.recommended.rules
    }
  },
  {
    plugins: {
      "simple-import-sort": simpleImportSort
    },
    rules: {
      "simple-import-sort/imports": "error",
      "simple-import-sort/exports": "error",
      "@typescript-eslint/consistent-type-imports": [
        "error",
        { prefer: "type-imports", fixStyle: "separate-type-imports" }
      ],
      "@typescript-eslint/no-floating-promises": "error",
      "@typescript-eslint/no-misused-promises": [
        "error",
        { checksVoidReturn: { attributes: false } }
      ],
      "@typescript-eslint/no-unused-vars": [
        "error",
        { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }
      ],
      "no-console": ["warn", { allow: ["warn", "error"] }]
    }
  },
  {
    files: ["**/*.{js,mjs,cjs}"],
    extends: [tseslint.configs.disableTypeChecked]
  },
  {
    files: ["**/*.{test,spec}.{ts,tsx}", "**/__tests__/**/*.{ts,tsx}"],
    rules: {
      "@typescript-eslint/no-explicit-any": "off",
      "@typescript-eslint/no-unsafe-assignment": "off",
      "@typescript-eslint/no-unsafe-member-access": "off"
    }
  }
);

この設定の狙いは、スタイルの好みよりも「実害のあるミス」を優先することです。no-floating-promisesawait忘れを拾い、no-misused-promisesはReactのイベントハンドラに非同期関数をそのまま渡す事故を減らします。consistent-type-importsは型だけのimportを明確にし、ビルド結果やバンドルの読みやすさを保ちます。

Astroサイトでは.astroを別扱いする

Astroは.astroファイルの中にHTML風テンプレート、TypeScript、コンポーネント呼び出しが混ざります。Reactの.tsxと同じ設定をそのまま当てると、パーサーが.astroを読めずに失敗します。

Astroのコンテンツサイトなら、次のようにAstro推奨設定を先に広げ、.astro専用のルールを足します。

import js from "@eslint/js";
import astro from "eslint-plugin-astro";
import globals from "globals";
import tseslint from "typescript-eslint";

export default tseslint.config(
  {
    ignores: ["dist/", ".astro/", "node_modules/", "public/"]
  },
  js.configs.recommended,
  ...astro.configs["flat/recommended"],
  ...astro.configs["jsx-a11y-recommended"],
  ...tseslint.configs.recommendedTypeChecked,
  {
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node
      },
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname
      }
    }
  },
  {
    files: ["**/*.astro"],
    languageOptions: {
      parserOptions: {
        parser: tseslint.parser,
        extraFileExtensions: [".astro"],
        projectService: true,
        tsconfigRootDir: import.meta.dirname
      }
    },
    rules: {
      "astro/no-set-html-directive": "error",
      "astro/no-unused-define-vars-in-style": "error"
    }
  }
);

手順記事やブログのようにMDXやAstroを多く扱うサイトでは、ESLintだけで整形まで完璧にしようとしない方が安定します。整形はPrettier設定カスタマイズガイドのようにPrettierへ任せ、ESLintは危険なコード、アクセシビリティ、型の事故に寄せます。

実例3つ: どのルールを強めるか

実例1はSaaS管理画面です。ユーザー招待、請求、権限変更のような処理では、Promiseの握りつぶしが本番事故につながります。@typescript-eslint/no-floating-promiseserrorにし、クリック時の非同期処理はvoid handleSubmit()のように意図を明示します。

実例2はAstroの技術ブログです。記事本文、OGP、CTAコンポーネントが混ざるので、.astroのパース失敗を最初に解消します。astro/no-set-html-directiveを強めると、安易なHTML注入をレビューで見落としにくくなります。

実例3はライブラリ開発です。公開APIでは型importの揺れ、未使用export、テストだけで使うanyが残りがちです。本体は厳しく、テストだけ一部緩める分離が効きます。設定全体を緩めると、ライブラリ利用者に届く型定義まで荒れます。

現場強めるルール緩める場所
React管理画面Promise、Hooks、a11yStorybookのmock
Astroブログ.astro、HTML注入、未使用CSS生成済みコンテンツ
TypeScriptライブラリ型import、未使用変数、exporttest fixture

この分け方は、コミット時の自動実行とも相性がよいです。Huskyやlint-stagedを使う場合はHusky + lint-staged設定ガイドも合わせて確認してください。

CIで検証する

ローカルで直っても、CIで同じコマンドが走らなければチームの品質はそろいません。GitHub Actionsなら次の最小構成で十分です。

name: code-quality

on:
  pull_request:
  push:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck

既存コードに違反が多い場合は、いきなり--fixで全体を書き換えないでください。最初はnpm run lint -- --format jsonで違反の種類を集計し、Claude Codeには「危険度が高いルールから小さく直す」と依頼します。

npm run lint
npm run lint:fix
npm run lint
npm run typecheck
npm run lint:debug

lint:debugで出した.eslint-debug.jsonは、設定が想定通り当たっているかを見るための一時資料です。React用ルールが.astroに当たっていないか、テストだけ緩めたルールが本体に漏れていないかを確認できます。

Claude Codeへの修正依頼テンプレ

テンプレート1: 新規導入。

このリポジトリにESLint Flat Configを導入してください。
対象はTypeScript + Reactです。まずpackage.json、tsconfig、既存のlint設定を読んでください。
eslint.config.mjsを作成し、npm run lint / npm run typecheckが通るまで修正してください。
既存の挙動を変える自動修正は避け、必要な場合は理由を説明してください。

テンプレート2: lintエラー修正。

npm run lintの結果を貼ります。
エラーをルール別に分類し、影響の小さい順に修正してください。
eslint-disableは最後の手段にし、使う場合は1行コメントで理由を書いてください。
修正後にnpm run lintとnpm run typecheckを実行してください。

テンプレート3: Astro対応。

AstroサイトのESLint設定を見直してください。
.astro、.ts、.tsxで適用される設定を分け、eslint-plugin-astroの推奨設定を使ってください。
astro/no-set-html-directiveをerrorにし、React用ルールが.astro全体に誤って当たらないか確認してください。

テンプレート4: CI失敗の調査。

GitHub Actionsのlint jobが失敗しています。
ローカルとCIでNode/npm/ESLintのバージョン差を確認し、再現手順を作ってください。
設定変更、依存更新、コード修正のどれが必要かを分けて提案し、最小差分で直してください。

Claude Codeには「直して」だけではなく、「何を読んで、どのコマンドで、どこまで許すか」を渡すのが重要です。これだけで、不要なルール削除や大きすぎる自動修正をかなり減らせます。

よくある落とし穴

一つ目は.eslintrc時代のextendsをそのまま貼ることです。Flat Configでは設定の形が違います。古い共有設定を使う必要がある場合は互換レイヤーを検討しますが、まずはFlat Config対応済みの公式例を選びます。

二つ目は型情報ありのlintを全ファイルに当てることです。projectService: trueは便利ですが、生成物、Storybook出力、ビルド済みJSまで読むと遅くなります。ignoresを先に書く方が、後からCI時間を削るより楽です。

三つ目はeslint --fixを巨大差分で走らせることです。import順、未使用変数、型importが一気に変わると、レビューが「挙動差分」ではなく「整形差分」に埋もれます。Masaは初回導入ではルール単位で小さくPRを分けるようにしています。

四つ目は警告を放置することです。warnは便利ですが、半年後には誰も見なくなります。CIで止めるべきものはerror、教育目的で眺めるだけならwarn、不要なら入れない、という3択にします。

五つ目はClaude Codeに設定の意図を渡さないことです。「Reactだからおすすめで」ではなく、「アクセシビリティを落としたくない」「テストfixtureのanyは許す」「公開APIは厳しくする」と伝えると、設定が現場に合います。

まとめ

ESLint Flat Configは、1ファイルに設定を集められるぶん、ルールの責任範囲も見えやすくなりました。Claude Codeを使う価値は、設定を一発生成させることではなく、既存コード、CI、チームのレビュー基準に合わせて、壊さない順番で導入できる点にあります。

まずはReact/TypeScriptかAstroかを分け、npm run lintnpm run typecheckをCIに固定してください。次にClaude Codeへテンプレート付きで修正を依頼し、eslint-disableと巨大な--fix差分だけは人間がレビューします。

より広い開発環境を整えるなら、整形はPrettier設定カスタマイズガイド、コミット前チェックはHusky + lint-staged設定ガイドへ進むのが自然です。繰り返し使えるレビュー依頼文や導入チェックリストが必要なら、ClaudeCodeLabの教材ページでプロンプト集と導入テンプレートも確認できます。

実際に試した結果

この記事の設定をMasaの検証用React管理画面とAstroブログ雛形に入れて試したところ、初回はimport順と未処理Promiseが多く出ました。eslint --fixだけで直した差分はレビューしづらかったため、Promise、import、Astro安全ルールの順に分ける方が安定しました。最終的にはnpm run lintnpm run typecheckをCIで固定し、Claude Codeには失敗ログを貼って小さく修正させる運用が一番再現性が高かったです。

#Claude Code #ESLint #コード品質 #TypeScript #開発環境
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。