T-CREATOR

ESLint を Yarn + TypeScript + React でゼロから構築:Flat Config 完全手順(macOS)

ESLint を Yarn + TypeScript + React でゼロから構築:Flat Config 完全手順(macOS)

TypeScript と React を活用した開発環境において、コード品質の維持は極めて重要です。ESLint はそのための強力なツールですが、2024 年以降は新しい「Flat Config」形式への移行が推奨されています。

従来の .eslintrc.js.eslintrc.json といった設定ファイルは、複数のファイル形式が混在し、設定の優先順位が複雑でした。新しい Flat Config では、単一の eslint.config.js ファイルで一元管理でき、TypeScript との親和性も向上しています。本記事では、macOS 環境で Yarn を使い、完全にゼロから ESLint を Flat Config で構築する手順を解説します。

背景

ESLint の進化と Flat Config の登場

ESLint は JavaScript と TypeScript のコード品質を保つ静的解析ツールとして、長年にわたり開発現場で利用されてきました。しかし、従来の設定方式(.eslintrc 系)には、以下のような課題がありました。

  • 複数の設定ファイル形式(JSON、YAML、JS)が混在し、管理が煩雑
  • extends による設定の継承順序が直感的でない
  • プラグインとパーサーの関係が暗黙的で、初学者には理解しづらい

こうした背景から、ESLint v8.23.0 で導入されたのが Flat Config です。この新形式は、設定を JavaScript の配列として明示的に記述し、各設定オブジェクトを順番に適用するシンプルな仕組みになっています。

以下の図は、従来の .eslintrc 形式と新しい Flat Config の設定構造を比較したものです。

mermaidflowchart LR
  oldConfig["従来の .eslintrc"] -->|複数形式| json[".eslintrc.json"]
  oldConfig -->|複数形式| yaml[".eslintrc.yaml"]
  oldConfig -->|複数形式| js[".eslintrc.js"]
  oldConfig -->|extends| implicit["暗黙的な継承"]

  newConfig["Flat Config"] -->|単一ファイル| eslintConfig["eslint.config.js"]
  eslintConfig -->|配列で明示| explicit["明示的な設定オブジェクト"]
  explicit -->|順番に適用| rules["ルール適用"]

TypeScript と React における ESLint の重要性

TypeScript と React を組み合わせた開発では、型安全性とコンポーネント設計の両方を考慮する必要があります。ESLint は、以下のような役割を果たします。

#役割具体例
1型の誤用を早期発見any 型の過度な使用を警告
2React のベストプラクティスを強制Hooks のルール違反を検出
3コードスタイルの統一インデントや命名規則の統一
4バグの予防未使用変数や到達不能コードの検出

特に React では、Hooks のルール(useEffect の依存配列など)を正しく守らないと、意図しないバグが発生します。ESLint はこれらを自動的にチェックし、開発者の負担を軽減してくれます。

Flat Config がもたらすメリット

Flat Config は、単なる設定形式の変更ではなく、以下のような実質的なメリットをもたらします。

  • 設定の可視化: すべての設定が配列として一箇所に集約され、どのルールがどの順番で適用されるかが明確
  • TypeScript との親和性向上: ES Modules を前提とした設計で、import 文による型安全な設定が可能
  • プラグインの扱いやすさ: プラグインを import して直接利用でき、設定の依存関係が明示的
  • 段階的な適用: ファイルパターンごとに異なる設定を柔軟に適用可能

これらのメリットにより、特に大規模プロジェクトや複数人での開発において、ESLint の設定管理が大幅に改善されます。

課題

従来の .eslintrc 形式における問題点

従来の .eslintrc 形式では、いくつかの構造的な問題がありました。特に TypeScript と React を組み合わせた環境では、以下のような課題が顕在化していました。

設定ファイルの複雑さ

.eslintrc.js では、extends による設定の継承が多段階になると、どのルールがどこから来ているのかを追跡するのが困難でした。

javascript// 従来の .eslintrc.js の例
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
  ],
  // どのルールがどこから来ているか分かりにくい
};

この設定では、4 つの異なる設定セットが順番に適用されますが、それぞれがどのようなルールを含んでいるかは、プラグインのドキュメントを個別に確認しなければなりません。

プラグインとパーサーの暗黙的な依存関係

TypeScript を使用する場合、@typescript-eslint​/​parser をパーサーとして指定する必要がありますが、この設定とプラグインの関係が暗黙的でした。

javascript// パーサーとプラグインの関係が不明瞭
module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  // なぜこの組み合わせが必要なのか分かりにくい
};

ファイルパターンごとの設定の困難さ

.ts ファイルと .tsx ファイルで異なる設定を適用したい場合、overrides を使う必要がありましたが、記述が冗長になりがちでした。

javascript// overrides を使った従来の記述
module.exports = {
  overrides: [
    {
      files: ['*.ts', '*.tsx'],
      rules: {
        '@typescript-eslint/explicit-function-return-type':
          'warn',
      },
    },
    {
      files: ['*.tsx'],
      rules: {
        'react/prop-types': 'off',
      },
    },
  ],
};

以下の図は、従来の設定形式における問題点を視覚化したものです。

mermaidflowchart TD
  config["eslintrc.js"] -->|extends| base["eslint:recommended"]
  config -->|extends| ts["@typescript-eslint/recommended"]
  config -->|extends| react["react/recommended"]
  config -->|extends| hooks["react-hooks/recommended"]

  base -->|ルール適用| rules1["基本ルール群"]
  ts -->|ルール適用| rules2["TypeScript ルール群"]
  react -->|ルール適用| rules3["React ルール群"]
  hooks -->|ルール適用| rules4["Hooks ルール群"]

  rules1 -.->|競合?| conflict["ルール競合の可能性"]
  rules2 -.->|競合?| conflict
  rules3 -.->|競合?| conflict
  rules4 -.->|競合?| conflict

  conflict -->|不明瞭| developer["開発者の混乱"]

初学者にとってのハードル

ESLint の設定は、初学者にとって特に難解な部分でした。

#ハードル具体的な困難
1設定ファイル形式の選択JSON、YAML、JS のどれを使うべきか判断できない
2プラグインの理解プラグインとパーサーの違いが分からない
3extends の順序どの順番で設定を継承すべきか不明
4ルールのカスタマイズどのルールを有効化すべきか判断できない

これらのハードルにより、多くの開発者は「とりあえず動く設定」をコピー&ペーストして使うことになり、設定の理解が深まらないという悪循環に陥っていました。

Flat Config への移行の必要性

ESLint の公式チームは、ESLint v9 以降で Flat Config をデフォルトにする方針を示しています。つまり、従来の .eslintrc 形式は将来的に非推奨となる可能性が高いのです。

早めに Flat Config へ移行することで、以下のメリットが得られます。

  • 将来的な非推奨化への備え
  • より明確で保守性の高い設定
  • TypeScript を活用した型安全な設定管理
  • モダンな JavaScript(ES Modules)の活用

次のセクションでは、これらの課題を解決する Flat Config の具体的な設定方法を解説します。

解決策

Flat Config の基本構造

Flat Config では、設定を 配列形式 で記述します。各配列要素が 1 つの設定オブジェクトとなり、上から順番に適用されていきます。

javascript// eslint.config.js の基本構造
export default [
  {
    // 設定オブジェクト 1
    files: ['**/*.js'],
    rules: {
      /* ... */
    },
  },
  {
    // 設定オブジェクト 2
    files: ['**/*.ts', '**/*.tsx'],
    rules: {
      /* ... */
    },
  },
];

この構造により、設定の適用順序が一目瞭然になります。後から定義された設定が前の設定を上書きするため、優先順位の理解も容易です。

以下の図は、Flat Config における設定の適用フローを示したものです。

mermaidflowchart TD
  start["eslint.config.js"] -->|配列の 1 番目| config1["基本設定オブジェクト"]
  config1 -->|配列の 2 番目| config2["TypeScript 用設定"]
  config2 -->|配列の 3 番目| config3["React 用設定"]
  config3 -->|配列の 4 番目| config4["カスタムルール"]

  config1 -->|適用| apply1["基本ルール適用"]
  config2 -->|適用| apply2["TS ルール追加"]
  config3 -->|適用| apply3["React ルール追加"]
  config4 -->|適用| apply4["カスタムルール上書き"]

  apply4 -->|最終結果| final["統合された ESLint 設定"]

図で理解できる要点:

  • 設定は配列の順番通りに適用される
  • 後の設定が前の設定を上書きできる
  • 最終的に統合された 1 つの設定として機能する

設定オブジェクトの主要プロパティ

Flat Config の各設定オブジェクトには、以下のようなプロパティを指定できます。

#プロパティ役割
1files対象ファイルパターン['**​/​*.ts', '**​/​*.tsx']
2ignores除外パターン['node_modules​/​**']
3languageOptionsパーサーや環境設定{ parser, ecmaVersion }
4plugins使用するプラグイン{ '@typescript-eslint': plugin }
5rules適用するルール{ 'no-console': 'warn' }

これらのプロパティを組み合わせることで、柔軟かつ明示的な設定が可能になります。

TypeScript と React に特化した設定戦略

TypeScript と React を使う場合、以下の 3 つのレイヤーで設定を構築すると整理しやすくなります。

レイヤー 1:基本設定

JavaScript の基本的なルールセットを適用します。

javascript// ESLint の推奨設定をインポート
import js from '@eslint/js';

export default [
  js.configs.recommended, // 基本の推奨設定
];

この設定により、未使用変数や到達不能コードなど、JavaScript の基本的な問題を検出できます。

レイヤー 2:TypeScript 設定

TypeScript 固有のルールを追加します。

javascript// TypeScript ESLint のプラグインをインポート
import tseslint from 'typescript-eslint';

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended, // TypeScript の推奨設定を展開
];

... スプレッド構文を使うことで、複数の設定オブジェクトを配列に展開できます。これにより、TypeScript 特有の型チェックルールが有効になります。

レイヤー 3:React 設定

React と React Hooks のルールを追加します。

javascript// React プラグインをインポート
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    files: ['**/*.tsx'], // React コンポーネントファイルのみ対象
    plugins: {
      react,
      'react-hooks': reactHooks,
    },
    rules: {
      ...react.configs.recommended.rules,
      ...reactHooks.configs.recommended.rules,
    },
  },
];

この 3 層構造により、各技術スタックに対応したルールが段階的に適用されます。

モジュールベースのインポート

Flat Config では、ES Modules の import 文を使ってプラグインや設定をインポートします。これにより、以下のメリットが得られます。

  • 型安全性の向上: TypeScript と組み合わせることで、設定の型チェックが可能
  • 依存関係の明示化: どのパッケージが必要かが import 文で明確
  • IDE のサポート: エディタの補完機能が効きやすい
javascript// import 文により依存関係が明示的
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';

// 各設定を組み合わせて配列を作成
export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
  react.configs.flat.recommended, // Flat Config 対応の設定
];

ファイルパターンによる柔軟な設定適用

Flat Config では、files プロパティを使って、ファイルパターンごとに異なる設定を簡潔に記述できます。

javascript// TypeScript ファイルと TSX ファイルで異なる設定を適用
export default [
  {
    files: ['**/*.ts'], // .ts ファイルのみ
    rules: {
      '@typescript-eslint/explicit-function-return-type':
        'warn',
    },
  },
  {
    files: ['**/*.tsx'], // .tsx ファイルのみ
    rules: {
      '@typescript-eslint/explicit-function-return-type':
        'off',
      'react/prop-types': 'off', // TypeScript で型チェックするため不要
    },
  },
];

このように、ファイルの種類に応じて適切なルールセットを適用することで、無駄な警告を減らし、開発効率を高められます。

具体例

環境準備:プロジェクトの初期化

まず、macOS で Node.js と Yarn がインストールされていることを確認します。

bash# Node.js のバージョン確認(v18 以上推奨)
node --version

# Yarn のバージョン確認(v1.22 以上または v3/v4)
yarn --version

新規プロジェクトを作成し、必要なパッケージをインストールします。

bash# プロジェクトディレクトリを作成して移動
mkdir eslint-flatconfig-demo && cd eslint-flatconfig-demo

# package.json を生成
yarn init -y

この手順により、空の package.json が作成されます。次に、TypeScript と React の開発環境を整えていきます。

必要なパッケージのインストール

Flat Config で ESLint を構築するために必要なパッケージを一括でインストールします。

bash# ESLint 本体と関連パッケージをインストール
yarn add -D eslint @eslint/js

# TypeScript と型定義をインストール
yarn add -D typescript @types/node @types/react @types/react-dom

# TypeScript ESLint プラグインをインストール
yarn add -D typescript-eslint

# React と React Hooks のプラグインをインストール
yarn add -D eslint-plugin-react eslint-plugin-react-hooks

# React 本体をインストール(動作確認用)
yarn add react react-dom

各パッケージの役割は以下の通りです。

#パッケージ役割
1eslintESLint 本体
2@eslint​/​jsJavaScript の推奨設定
3typescript-eslintTypeScript 用 ESLint プラグインと設定
4eslint-plugin-reactReact 用 ESLint プラグイン
5eslint-plugin-react-hooksReact Hooks 用 ESLint プラグイン

TypeScript の設定

TypeScript の基本設定ファイル tsconfig.json を作成します。

bash# TypeScript の設定ファイルを生成
yarn tsc --init

生成された tsconfig.json を以下のように編集します。

json{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "jsx": "react-jsx",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

この設定により、React と TypeScript を組み合わせた開発環境が整います。

Flat Config ファイルの作成

プロジェクトのルートに eslint.config.js を作成します。

bash# ESLint 設定ファイルを作成
touch eslint.config.js

以下の内容を eslint.config.js に記述します。

基本設定とインポート

javascript// ESLint の基本設定と TypeScript、React のプラグインをインポート
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import globals from 'globals';

この部分では、必要なプラグインと設定をインポートしています。globals は、ブラウザや Node.js のグローバル変数を定義するためのパッケージです(別途 yarn add -D globals でインストールが必要)。

設定配列の構築

javascript// Flat Config の配列を定義
export default [
  // 1. ESLint の推奨設定を適用
  js.configs.recommended,

  // 2. TypeScript の推奨設定を適用
  ...tseslint.configs.recommended,

  // 3. すべての JavaScript/TypeScript ファイルに共通の設定
  {
    files: ['**/*.{js,jsx,ts,tsx}'],
    languageOptions: {
      ecmaVersion: 2020,
      sourceType: 'module',
      globals: {
        ...globals.browser,
        ...globals.node,
      },
    },
  },

  // 4. React ファイル(.jsx, .tsx)専用の設定
  {
    files: ['**/*.{jsx,tsx}'],
    plugins: {
      react,
      'react-hooks': reactHooks,
    },
    settings: {
      react: {
        version: 'detect', // React のバージョンを自動検出
      },
    },
    rules: {
      ...react.configs.recommended.rules,
      ...reactHooks.configs.recommended.rules,
      'react/react-in-jsx-scope': 'off', // React 17+ では不要
      'react/prop-types': 'off', // TypeScript で型チェックするため不要
    },
  },

  // 5. TypeScript ファイル専用のカスタムルール
  {
    files: ['**/*.{ts,tsx}'],
    rules: {
      '@typescript-eslint/no-unused-vars': [
        'warn',
        {
          argsIgnorePattern: '^_',
          varsIgnorePattern: '^_',
        },
      ],
      '@typescript-eslint/explicit-function-return-type':
        'off',
      '@typescript-eslint/no-explicit-any': 'warn',
    },
  },

  // 6. 除外設定
  {
    ignores: ['node_modules/**', 'dist/**', 'build/**'],
  },
];

この設定では、以下のような段階的なルール適用を行っています。

mermaidflowchart TD
  start["eslint.config.js"] -->|1| jsConfig["ESLint 基本設定<br/>(js.configs.recommended)"]
  jsConfig -->|2| tsConfig["TypeScript 設定<br/>(tseslint.configs.recommended)"]
  tsConfig -->|3| commonConfig["共通設定<br/>(globals, ecmaVersion)"]
  commonConfig -->|4| reactConfig["React 設定<br/>(jsx, tsx ファイル)"]
  reactConfig -->|5| tsCustom["TypeScript カスタムルール<br/>(unused-vars など)"]
  tsCustom -->|6| ignore["除外設定<br/>(node_modules, dist)"]

  ignore --> final["最終的な ESLint 設定"]

図で理解できる要点:

  • 基本設定から始めて段階的に専門的な設定を追加
  • React と TypeScript のルールは個別のオブジェクトで管理
  • 最後に除外設定で不要なファイルをスキップ

サンプルコードの作成と検証

ESLint が正しく動作するか確認するため、サンプルの React コンポーネントを作成します。

bash# src ディレクトリを作成
mkdir src

サンプルコンポーネントの作成

src​/​App.tsx を作成し、以下のコードを記述します。

typescript// React コンポーネントのサンプル
import { useState } from 'react';

// Props の型定義
interface CounterProps {
  initialCount?: number;
}

// カウンターコンポーネント
export function Counter({
  initialCount = 0,
}: CounterProps) {
  const [count, setCount] = useState(initialCount);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}

このコンポーネントは、ESLint がどのようにルールを適用するかを確認するためのシンプルな例です。

ESLint の実行

設定が完了したら、ESLint を実行してコードをチェックします。

bash# src ディレクトリ内のすべてのファイルをチェック
yarn eslint src/

問題がなければ、何も出力されずに正常終了します。もし警告やエラーがある場合は、以下のようなメッセージが表示されます。

text/Users/username/eslint-flatconfig-demo/src/App.tsx
  5:10  warning  'unusedVar' is assigned a value but never used  @typescript-eslint/no-unused-vars

自動修正の活用

ESLint には、修正可能な問題を自動的に直す機能があります。

bash# --fix オプションで自動修正を実行
yarn eslint src/ --fix

この機能により、インデントやセミコロンの有無など、機械的に修正できる問題が自動的に解決されます。

package.json にスクリプトを追加

開発効率を上げるため、package.json に ESLint 実行用のスクリプトを追加します。

json{
  "scripts": {
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix"
  }
}

これにより、以下のように簡潔にコマンドを実行できます。

bash# ESLint を実行
yarn lint

# 自動修正も行う
yarn lint:fix

VS Code との統合

VS Code を使用している場合、ESLint 拡張機能をインストールすることで、エディタ上でリアルタイムに問題を検出できます。

  1. VS Code の拡張機能で「ESLint」を検索してインストール
  2. .vscode​/​settings.json を作成し、以下を記述
json{
  "eslint.experimental.useFlatConfig": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

この設定により、ファイル保存時に自動的に ESLint の修正が適用されます。

トラブルシューティング

エラー:Failed to load config

ESLint が設定ファイルを読み込めない場合、以下を確認します。

  • eslint.config.js がプロジェクトのルートにあるか
  • package.json"type": "module" が設定されているか(必要に応じて追加)

エラー:Parsing error: Cannot find module

TypeScript のパーサーが見つからない場合、typescript-eslint が正しくインストールされているか確認します。

bash# パッケージの再インストール
yarn add -D typescript-eslint

警告:React version not specified

React のバージョンが検出されない場合、eslint.config.jssettings セクションを確認します。

javascriptsettings: {
  react: {
    version: 'detect', // または '18.0' など具体的なバージョン
  },
},

まとめ

本記事では、macOS 環境で Yarn、TypeScript、React を使い、ESLint を Flat Config で構築する完全な手順を解説しました。

Flat Config の主なメリットは以下の通りです。

  • 設定の一元管理: 単一の eslint.config.js ファイルですべてを管理
  • 明示的な設定: 配列形式により、ルールの適用順序が明確
  • TypeScript との親和性: ES Modules と import 文による型安全な設定
  • 柔軟なファイルパターン適用: files プロパティで簡潔に対象を指定

従来の .eslintrc 形式に慣れている方も、Flat Config に移行することで、より保守性の高い設定を構築できます。ESLint v9 以降では Flat Config がデフォルトになる予定ですので、早めの移行をお勧めします。

今回紹介した設定を基に、プロジェクトの要件に合わせてカスタマイズを進めていただければと思います。コード品質の向上と開発効率の改善に、本記事が役立つことを願っています。

関連リンク