ESLint設定まとめ:基本設定からルール設定の進め方まで
要点まとめ
ESLint の設定理解で最も重要なこと
ESLint の設定ファイルには 4 つの設定項目があり、それぞれなぜ必要なのかを理解することが、プロジェクトに合った設定を作れる鍵になります:
-
環境指定 (env):プロジェクトの実行環境(ブラウザ/Node.js)や ECMAScript バージョンを認識させるため
- これがないと、
windowやdocumentが「未定義」と誤判定される
- これがないと、
-
パーサ設定 (parser):TypeScript や JSX など、標準 JavaScript とは異なる構文に対応するため
- これがないと、TypeScript の型注記がパースエラーになる
-
解析対象 (files):プロジェクト内のどのファイルに対して設定を適用するかを指定するため
- これがないと、.ts と .js が混在するとき、どのファイルに対してどの設定を適用すべきか曖昧になる
-
ルール設定 (rules):チームやプロジェクトの「コード品質基準」を具体的に定義するため
- これがないと、ESLint がコードをどう評価すべきか不明になる
はじめに
ESLint の設定を始めるとき、
- どのプリセットを使うべきか
- ルールをどこまで厳しくするべきか
といった判断に迷うことがあります。
多くの場合、その原因は ESLintの4つの設定項目がそれぞれ何を担当しているのかを理解しないまま設定を進めてしまうことにあります。
本記事では、ESLint設定の基本構造を整理しながら、
- 環境指定(env)とパーサ設定が必要な理由
- 解析対象(files)をプロジェクトに合わせる意味
- ルール設定で「コード品質基準」を定義する手順
- TypeScript と ESLint を組み合わせるときの考え方
を、判断基準と実装例を通して解説します。
ESLint設定の全体構造
ESLint の設定は、主に次の 4 つの役割に分けて考えることができます。それぞれが異なる責務を持ち、すべて揃うことで ESLint が正しく機能します:
┌────────────────────────────────────┐
│ 1. 環境・パーサ設定 │
│ env / parser / languageOptions │
│ │
│ どんなコードを解析できるかを決める │
└──────────────┬──────────────────────┘
│
▼
┌────────────────────────────────────┐
│ 2. 解析対象の指定 │
│ files / ignores │
│ │
│ どのファイルを解析するか決める │
└──────────────┬──────────────────────┘
│
▼
┌────────────────────────────────────┐
│ 3. プリセット / プラグイン │
│ extends / plugins │
│ │
│ ルールセットを追加する │
└──────────────┬──────────────────────┘
│
▼
┌────────────────────────────────────┐
│ 4. ルール設定 │
│ rules │
│ │
│ コード品質の基準を定義する │
└────────────────────────────────────┘
設定項目
ESLintの設定ファイルには、主に次の4つの項目が含まれます。それぞれ異なる役割を担当しており、どれが欠けても ESLint が正しく機能しません:
- グローバル変数(環境指定): プロジェクトの実行環境(ブラウザ/Node.js)を ESLint に認識させ、環境固有のグローバル変数(
window、documentなど)をエラーと判定しないようにする - 構文解析エンジン(パーサ): TypeScript や JSX など、標準 JavaScript とは異なる構文を正しく解析するためのエンジンを指定する
- 解析対象のファイル: プロジェクト内のどのファイルに対して設定(パーサやルール)を適用するかを決める
- ルール: チームやプロジェクトが「良いコード」とみなす基準を、具体的なルールに翻訳して適用する
グローバル変数
必要な理由: プロジェクトの実行環境を ESLint に伝えることで、環境固有のグローバル変数をエラーと誤判定しないようにする
ESLint は「変数が定義されているかどうか」をチェックするルール (no-undef) を持っています。しかし、ブラウザの window、Node.js の require など、環境によって用意されているグローバル変数を知らないと、「そんな変数は存在しない」と誤判定してしまいます。
このセクションで「このプロジェクトはブラウザで動くためwindowは存在する」「Node.js 環境のためprocessは存在する」を指定することで、ESLint が認識できるようにします。
設定例(.eslintrc の場合):
"env": {
"browser": true, // `window`, `document` などを使用可能にする
"node": true, // `require`, `process` などを使用可能にする
"es2022": true // ES2022 の構文を許可
}
指定しない場合の問題:
例えば、"browser": trueを指定しないと、以下のようなコードでエラーが発生します
console.log(window.location.href);
// ESLint エラー: 'window' is not defined. (no-undef)
コード自体には何の問題もありません。ESLint が window の存在を認識していないだけです。
構文解析エンジン
必要な理由: TypeScript や JSX など、標準 JavaScript とは異なる構文を正しく解析できるようにするため
ESLint はコードをチェックするために、まずコード全体を「構文解析(パース)」して理解する必要があります。デフォルトでは、標準 JavaScript の構文を解析する espree が使われます。しかし、TypeScript のような言語を使う場合、デフォルトのパーサは TypeScript の構文(型注記など)を理解できません。
言語に合わせてパーサを変更することで、その言語の構文を正しく解析できるようにします。
設定例(.eslintrc の場合):
"parser": "@typescript-eslint/parser"
Flat Config では、以下のように文字列ではなくインポートしたオブジェクトを直接渡します:
import tsParser from "@typescript-eslint/parser";
export default [
{
languageOptions: {
parser: tsParser,
},
},
];
指定しない場合の問題:
例えば、"parser": "@typescript-eslint/parser"を指定せずに TypeScript ファイルをチェックすると、以下のようなコードでエラーが発生します
const message: string = "Hello";
// ESLint エラー: Parsing error: Unexpected token ':'
コード自体は正しい TypeScript です。デフォルトのパーサが : string という型注記の構文を認識していないだけです。
解析対象のファイル
必要な理由: プロジェクト内のどのファイルに対して設定を適用するかを指定するため
プロジェクトには .js や .ts、.jsx など複数の拡張子ファイルが存在する場合があります。ESLint では、設定オブジェクトごとに files を指定することで、その設定を適用する対象ファイルを制御できます。
重要な点:files の役割は「設定の適用範囲」を指定することであり、パーサを指定するものではありません。パーサの指定は languageOptions.parser で行います。
設定例:
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
parser: tseslint.parser
}
}
このように files を指定することで、特定のファイル拡張子に対して適切なパーサやルールを適用できます。
ルール
必要な理由:「良いコード」の基準をプロジェクト・チーム文化に合わせて、具体的なルールに翻訳して適用するため
ESLint には 300以上のルール があります。これらは「セミコロンを常に付ける」「変数は使う前に宣言する」「console.log を削除する」など、様々なコード品質基準を表しています。
プロジェクトの成熟度や団体文化によって「どのルールを重視するか」は異なります。このセクションで、プロジェクトに必要なルールを選び、重要度(off/warn/error)を設定します。
設定レベルの意味:
| 設定値 | 挙動 |
|---|---|
"off" |
ルールを適用しない(チェックしない) |
"warn" |
ルールに違反すると黄色の警告(VSCodeで波線、コンソールに警告) |
"error" |
ルールに違反すると赤いエラー(VSCodeで波線、コンソールにエラー、CIでは失敗) |
設定例:
"rules": {
"semi": ["error", "always"], // セミコロンを常に要求(違反は CI で失敗)
"quotes": ["error", "double"] // 文字列はダブルクォートを使用
}
最初は "warn" で導入し、チームに浸透したら "error" に昇格させるという段階的なアプローチが効果的です。
設定方法
- eslint.config.js(Flat Config)はv8で導入され、v9(2024年4月リリース)で .eslintrc のサポートが終了したため、移行が推奨
- 新しいプロジェクトでは eslint.config.js を採用するのが良さそう(Next.jsではv15からFlat Configに対応)
- Flat Configにするメリット
-
Lintを実行する前に設定ミスを発見できる
- .eslintrc では、pluginsやextendsを文字列で指定するため、Lint実行時にしかエラーが分からない
module.exports = { extends: ["plugin:import/recommended"], plugins: ["import"], // Failed to load plugin 'import': Cannot find module 'eslint-plugin-import' };- Flat Configではimportを使うため、エディタや型チェックで即エラーが分かる
import importPlugin from "eslint-plugin-import"; // Error: Cannot find module 'eslint-plugin-import' export default [ { plugins: { import: importPlugin, }, ...importPlugin.configs.recommended, }, ];
-
グローバル変数の設定方法
-
eslint.config.jsの場合
- languageOptions.globals
を使用して、環境ごとのグローバル変数を利用可能にする
- languageOptions.globals
-
例えば、ブラウザ向けのコードを書く場合、globals.browserを設定
import globals from "globals";
export default [
{
languageOptions: {
globals: {
...globals.browser, // `window`, `document` などを使用可能にする
...globals.es2022 // ES2022 のグローバル変数を許可
}
}
}
];
.eslintrc.jsの場合
module.exports = {
env: {
browser: true, // `window`, `document` などを使用可能にする
es2022: true // ES2022 の構文を許可
}
};
構文解析エンジンの設定方法
- eslint.config.jsの場合
- languageOptions.parser
- languageOptions.parserOptions
を使用して、適切な構文解析エンジンを設定
例えば、TypeScriptを使用する場合は@typescript-eslint/parserを設定
import tsParser from "@typescript-eslint/parser";
export default [
{
languageOptions: {
parser: tsParser,
parserOptions: {
project: "./tsconfig.json",
},
},
},
];
.eslintrc.js の場合
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json",
},
};
ちなみに構文解析エンジンが必要になるケース
標準のJavaScript構文解析エンジンで対応できない場合に指定
- .ts, .tsx (TypeScript) → @typescript-eslint/parser
- .vue (Vue) → vue-eslint-parser
- .svelte (Svelte) → svelte-eslint-parser
解析対象のファイルの設定方法
- eslint.config.jsの場合
- files
- ignores
を使用して、解析対象のファイルを設定
export default [
{
files: ['**/*.{ts,tsx}'],
ignores: ["dist"], // `node_modules`はデフォルトで除外
},
];
.eslintrc.js の場合
module.exports = {
// .eslintrc.js にはトップレベルの `files` がない。対象ファイルは次のいずれかで指定する。
// 【方法1】overrides で「この設定をどのファイルに適用するか」を指定
// overrides: [
// {
// files: ['**/*.ts'],
// parser: '@typescript-eslint/parser'
// }
// ]
// 【方法2】実行時に --ext で拡張子を指定
// eslint --fix --ext .jsx,.js,.tsx,.ts .
ignorePatterns: ["dist"], // `node_modules`はデフォルトで除外
};
ルールの設定方法
- eslint.config.jsの場合
- rules
- extends
- plugins
を使用して、ルールを設定
- extendsは後ろに書いたものが前の設定を上書きし、最終的なルールの適用はrulesが優先される
plugins・extends・rules の関係
plugins でルールセットを提供し、extends または rules(もしくは両方)でそのルールを実際に適用します。ESLint 本体の組み込みルール(no-console など)のみを使う場合は plugins は不要ですが、外部のルールセット(React 用など)を使う場合は plugins が必要です:
plugins(必須)
│
│ ルールセットを提供
▼
eslint-plugin-import
eslint-plugin-react
↓
【パターン A】extends を使う場合
│ プラグインの推奨設定を一括適用
▼
extends: ["plugin:import/recommended", "plugin:react/recommended"]
【パターン B】rules で個別指定する場合
│ 必要なルールだけを個別に指定
▼
rules: {
"import/order": "error",
"react/prop-types": "off"
}
【パターン C】extends + rules を組み合わせる場合
│ 推奨設定を使いつつ、個別ルールで上書き
▼
extends: ["plugin:import/recommended"]
rules: {
"import/order": "error" // 上書き
}
ポイント:
- plugins:ルールプロバイダーとして機能。ルール自体を提供するため必須
- extends:プラグインの推奨設定をまとめて適用。
rulesだけを使う場合は不要だが、どちらか一方は必須 - rules:個別ルール指定。
extendsだけを使う場合は不要だが、どちらか一方は必須。extendsとrulesの両方を使う場合、rulesが優先される
ルールの設定パターン
ESLintの標準ルールを変更する場合
ESLintに最初から含まれているルールの設定を変更する方法
- 一部変更する場合
-
rulesに設定
-
export default {
rules: {
"no-console": "error",
},
};
.eslintrc.js の場合
module.exports = {
rules: {
"no-console": "error",
},
};
- まとめて変更する場合
- Sharable Config(共有設定)を利用し、多くのルールをまとめて変更
import standard from "@eslint-config-standard";
export default [
standard,
];
.eslintrc.js の場合
module.exports = {
extends: "standard",
};
ESLintの標準ルールにないルールを追加する場合
ESLintに含まれていないルールを追加する方法、プラグインを導入して適用する
- 一部を変える場合
- プラグインを追加し、そのプラグイン内の特定のルールのみを
rulesで個別指定 - 推奨設定(
extends)は不要で、必要なルールだけを選択できる
- プラグインを追加し、そのプラグイン内の特定のルールのみを
import unusedImports from 'eslint-plugin-unused-imports';
export default [
{
plugins: {
'unused-imports': unusedImports,
},
rules: {
'unused-imports/no-unused-imports': 'error',
},
},
];
.eslintrc.jsの場合
module.exports = {
plugins: ["import"],
rules: {
"import/no-unresolved": "error",
},
};
- まとめて変更する場合
- プラグインを追加し、そのプラグイン内の推奨ルールをまとめて適用
import reactHooks from 'eslint-plugin-react-hooks'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{
plugins: {
'react-hooks': reactHooks,
},
rules: {
...reactHooks.configs.recommended.rules,
},
},
)
補足:tseslint.config は typescript-eslint 独自のラッパーヘルパーで、標準の配列形式をラップして型定義の恩恵を受けられるため、設定の入力時にエディタの自動補完やエラーチェックが可能になります。
or
import importPlugin from 'eslint-plugin-import';
export default [
importPlugin.flatConfigs.recommended,
];
.eslintrc.js の場合
module.exports = {
plugins: ["react-hooks", "import"],
extends: ["plugin:react-hooks/recommended", "plugin:import/recommended"],
};
Sharable Configやプラグイン適用時の注意点
- eslint-plugin-importのように、プラグインが内部でpluginsを追加しているケースもあるため、明示的にpluginsに記述しなくても適用されることがある
https://github.com/import-js/eslint-plugin-import/blob/4f145a2c64af4931f4bf3ae951c8b719b544718f/src/index.js#L86 - Sharable Configやプラグインの中には、他のプラグインをいくつかまとめて含んでいるものもある
- 例えば、eslint-config-next(https://nextjs.org/docs/app/api-reference/config/eslint) は
- eslint-plugin-next
- eslint-plugin-react
- eslint-plugin-react-hooks
- eslint-plugin-jsx-a11y
を含んでいる
→ ESLintの設定をシンプルに保つため、フレームワークやプラグインのアップデートを定期的に確認する
- 新しいルールが追加されると、以前手動で設定していたルールが不要になることがあるため、その際は設定を見直したほうがよさそう
- 例えば、eslint-config-next(https://nextjs.org/docs/app/api-reference/config/eslint) は
設定を成功させるポイント
ESLint の設定は、「正解」がなく、プロジェクトの成熟度やチーム文化に応じて調整するものです。以下の方針を参考に、段階的に進めると管理しやすくなります。
① ルールセットから始める
最初は eslint:recommended などの基本的なルールセットを適用します。これにより、ESLint の基本的なエラーをキャッチできます。
extends: ["eslint:recommended"]
② 必要なプラグインを追加する
React や TypeScript など、プロジェクトに応じたルールを追加します。このとき、各プラグインが推奨する設定をまとめて適用します。
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended"
]
③ rules で最終調整する
プロジェクトの方針やチーム文化に合わせて、個別ルールを調整します。
rules: {
"import/order": "error",
"react/prop-types": "off",
"@typescript-eslint/no-unused-vars": "warn"
}
段階的な導入のコツ
- 最初は
warnで導入する:error で導入すると、既存コードの対応に時間がかかる。warning から始めて、チームに浸透したら error に昇格させる - プリセット選択を戻さない:一度 extends で推奨設定を選んだら、後から削除するのではなく、rules で個別に
offにする方が管理しやすい - 定期的に見直す:フレームワークのアップデートやプラグインの新機能により、以前設定したルールが不要になることがある。定期的に見直すことが大切
ルール設定の進め方(個人開発)
-
使っている技術を整理し、各技術に応じたプラグインをawesome-eslintを参考に選定
- 例
- React → eslint-plugin-react
- TypeScript → @typescript-eslint/eslint-plugin
- Tailwind CSS → eslint-plugin-tailwindcss
- Jest → eslint-plugin-jest
- 例
-
その他良さそうなプラグインも選定
- 例
- import構文整理 → eslint-plugin-import, eslint-plugin-unused-imports
- アクセシビリティ関連 → eslint-plugin-jsx-a11y
- Prettier との競合を防ぐ → eslint-config-prettier(ESLint自体からフォーマットのルールは削除されたが、他のプラグインのフォーマット関連のルールを抑制するために必要)
- 例
-
既存のプラグインと機能が重複しないか確認し、最適な組み合わせを選定
-
プラグインの推奨設定や個別ルールの設定方法を確認
例: Vite + TypeScript + React の場合
- create-viteでテンプレートをつくると、次のeslint.config.jsが自動で作成される
eslint.config.js
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx,js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
{ ignores: ['dist'] },
)
tseslint.configについて
-
使っている技術を整理し、各技術に応じたプラグイン、その他良さそうなプラグインも適宜選定
技術 プラグイン React eslint-plugin-react TypeScript typescript-eslint import 構文整理 eslint-plugin-import, eslint-plugin-unused-imports アクセシビリティ eslint-plugin-jsx-a11y Prettier との競合防止 eslint-config-prettier -
プラグインの重複を確認し最適な組み合わせを選定
プラグイン 重複状況(@eslint/js, eslint-plugin-react-hooks, typescript-eslintとのルール重複) eslint-plugin-react 重複なし @typescript-eslint/eslint-plugin typescript-eslintに含まれるeslint-plugin-import 重複なし eslint-plugin-unused-imports 重複なし eslint-plugin-jsx-a11y 重複なし eslint-config-prettier 重複なし -
推奨設定の適用または個別ルールの設定の適用
- eslint-plugin-react
- eslint-plugin-import
- eslint-plugin-unused-imports
- eslint-plugin-jsx-a11y
- eslint-config-prettier
を適用する
サンプルコード
eslint.config.js 完成例 ─ 実務構成
ここまで説明した「4つの設定項目」を統合した実務的な eslint.config.js の例を示します。このセクションで学んだ役割を、実装に落とし込むことで、ESLint 設定を「理解して」構築できるようになります。
基本的な構成(Node.js + TypeScript)
import globals from 'globals';
import tseslint from 'typescript-eslint';
import js from '@eslint/js';
export default [
{
// 1. 環境・パーサ設定
files: ['**/*.{ts,js}'],
languageOptions: {
globals: {
...globals.node, // Node.js グローバル変数を有効化
...globals.es2022, // ES2022 構文を許可
},
parser: tseslint.parser, // TypeScript パーサを指定
parserOptions: {
project: './tsconfig.json',
},
},
// 2. プラグイン・プリセット設定
plugins: {
'@typescript-eslint': tseslint.plugin,
},
// 3. ルール設定
rules: {
...js.configs.recommended.rules,
...tseslint.configs.recommended.rules,
'@typescript-eslint/no-unused-vars': 'warn',
'no-console': 'warn',
},
},
{
// 4. Node.js テストファイル向け設定
files: ['**/*.test.ts', '**/*.spec.ts'],
languageOptions: {
globals: globals.node,
},
rules: {
'@typescript-eslint/no-empty-function': 'off',
},
},
{
// 5. 無視対象の設定
ignores: ['dist', 'build', 'node_modules'],
},
];
- 環境指定(
languageOptions.globals):Node.js 環境で実行されるコードであることを明示 - パーサ設定(
parser):TypeScript ファイルを正しく解析するために @typescript-eslint/parser を指定 - 解析対象(
files):**.tsと**.jsファイルに対してルールを適用、テストファイルは別設定 - ルール設定(
rules):プロジェクトとチーム文化に合わせたコード品質基準を定義 - プラグイン(
plugins):TypeScript 専用ルールを提供する @typescript-eslint プラグインを統合
TypeScript + Next.js の例
import globals from 'globals';
import tseslint from 'typescript-eslint';
import js from '@eslint/js';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import nextPlugin from '@next/eslint-plugin-next';
export default [
{
files: ['**/*.{ts,tsx,js,jsx}'],
languageOptions: {
globals: {
...globals.browser, // ブラウザグローバル(window, document など)
...globals.es2022,
},
parser: tseslint.parser,
parserOptions: {
project: './tsconfig.json',
ecmaFeatures: {
jsx: true, // JSX 構文を許可
},
},
},
plugins: {
'@typescript-eslint': tseslint.plugin,
'react': react,
'react-hooks': reactHooks,
'@next/next': nextPlugin,
},
rules: {
...js.configs.recommended.rules,
...tseslint.configs.recommended.rules,
...react.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
...nextPlugin.configs.recommended.rules,
'react/react-in-jsx-scope': 'off', // Next.js では不要
'@typescript-eslint/no-unused-vars': 'warn',
},
},
{
ignores: ['.next', 'dist', 'build'],
},
];
各プラグインが提供する推奨ルール(configs.recommended.rules)を統合することで、フレームワークの最適なルールセットを自動的に適用。その後、rules セクションでプロジェクト固有のカスタマイズ(例:React の react-in-jsx-scopeを無効化)を行っています。
重要なポイント:
- plugins と rules の分離:プラグインを読み込むだけでなく、どのルールを適用するかを明示的に指定
- ファイルごとの設定:異なる技術スタック(テストファイル、Next.js App Router など)に応じて、複数の設定ブロックを組み合わせる
- 段階的なカスタマイズ:最初は推奨設定を使い、プロジェクト成熟度に応じてカスタマイズを追加
参考資料
Discussion