ESLint パーサ比較:espree と @typescript-eslint/parser の互換性と速度
ESLint でコード品質を向上させる際、パーサの選択は重要な判断ポイントとなります。JavaScript プロジェクトではデフォルトの espree で十分ですが、TypeScript を使用する場合は@typescript-eslint/parser が必要になります。しかし、この 2 つのパーサにはどのような違いがあり、それぞれどのような特性を持っているのでしょうか。
本記事では、ESLint の 2 つの主要パーサである「espree」と「@typescript-eslint/parser」の互換性と速度について、実践的な観点から詳しく解説します。
背景
ESLint とパーサの役割
ESLint は、JavaScript コードの静的解析ツールとして広く使用されています。コードの問題を早期に発見し、一貫したコーディングスタイルを維持するために欠かせないツールですね。
ESLint がコードを解析する際、パーサ(Parser)が重要な役割を担います。パーサはソースコードを読み取り、抽象構文木(AST: Abstract Syntax Tree)と呼ばれるデータ構造に変換します。
以下の図は、ESLint がパーサを使ってコードを解析する基本的な流れを示しています。
mermaidflowchart LR
code["ソースコード"] -->|読み込み| parser["パーサ<br/>(espree または<br/>@typescript-eslint/parser)"]
parser -->|変換| ast["AST<br/>(抽象構文木)"]
ast -->|解析| rules["ESLintルール"]
rules -->|検出| errors["エラー・警告"]
このように、パーサはソースコードと ESLint ルールの橋渡しをする重要なコンポーネントです。
2 つのパーサの位置づけ
ESLint には主に 2 つのパーサが使用されます。
espreeは ESLint のデフォルトパーサで、JavaScript コードの解析に特化しています。ECMAScript 仕様に準拠し、最新の JavaScript 構文をサポートしていますね。
一方、@typescript-eslint/parserは TypeScript コードを解析するために開発されたパーサです。TypeScript の型情報や独自の構文を理解し、AST に変換する能力を持っています。
| # | パーサ名 | 対応言語 | デフォルト | 開発元 |
|---|---|---|---|---|
| 1 | espree | JavaScript | ★ | ESLint チーム |
| 2 | @typescript-eslint/parser | TypeScript, JavaScript | - | TypeScript ESLint チーム |
課題
パーサ選択の判断基準が不明確
多くの開発者が直面する課題として、プロジェクトでどのパーサを使用すべきか判断に迷うことがあります。特に、JavaScript と TypeScript が混在するプロジェクトでは、この選択がより複雑になりますね。
互換性に関する懸念
espree と@typescript-eslint/parser は異なる AST フォーマットを生成する場合があります。このため、特定の ESLint プラグインやルールが片方のパーサでしか動作しない可能性があります。
パフォーマンスへの影響
大規模なプロジェクトでは、パーサの処理速度が Lint の実行時間に大きく影響します。TypeScript パーサは型情報を解析するため、espree よりも処理時間が長くなる傾向があります。
以下の図は、パーサ選択時に考慮すべき主な課題を示しています。
mermaidflowchart TD
start["パーサ選択"] --> q1{"プロジェクトに<br/>TypeScriptを<br/>含むか?"}
q1 -->|Yes| q2{"型情報を<br/>活用したルールが<br/>必要か?"}
q1 -->|No| espree_choice["espree を選択"]
q2 -->|Yes| ts_parser["@typescript-eslint/parser<br/>必須"]
q2 -->|No| concern["互換性と速度の<br/>トレードオフを検討"]
concern --> decision["パーサ決定"]
ts_parser --> decision
espree_choice --> decision
これらの課題を理解することで、適切なパーサ選択が可能になります。
解決策
パーサの特性を理解する
それぞれのパーサの特性を正確に把握することが、適切な選択の第一歩となります。
espree の特性
espree は軽量で高速なパーサです。以下のような特徴を持っています。
javascript// .eslintrc.js でのespree設定(デフォルトのため通常は記載不要)
module.exports = {
parser: 'espree', // 明示的に指定する場合
parserOptions: {
ecmaVersion: 2024, // 最新のECMAScript構文をサポート
sourceType: 'module', // ESモジュールとして解析
},
};
espree の主な特性は以下の通りです。
- 高速な解析: TypeScript 特有の処理がないため、処理速度が速い
- ECMAScript 準拠: 標準的な JavaScript 構文を完全にサポート
- 軽量: 依存関係が少なく、インストールサイズが小さい
@typescript-eslint/parser の特性
@typescript-eslint/parser は TypeScript コードを解析するための強力な機能を提供します。
typescript// .eslintrc.js でのTypeScriptパーサ設定
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2024,
sourceType: 'module',
project: './tsconfig.json', // 型情報を活用する場合に必須
},
};
@typescript-eslint/parser の特性を以下にまとめます。
| # | 特性 | 説明 | メリット |
|---|---|---|---|
| 1 | TypeScript 構文サポート | interface、type、decorator などを解析 | TypeScript コードを正確に検証 |
| 2 | 型情報の活用 | tsconfig.json を読み込み型情報を利用 | 高度なルールチェックが可能 |
| 3 | JavaScript 互換 | JavaScript(.js)ファイルも解析可能 | 混在プロジェクトでも使用可能 |
互換性の確保方法
プラグインとの互換性
ESLint プラグインは特定のパーサに依存する場合があります。以下の原則で互換性を確保できます。
javascript// TypeScriptプロジェクトでの推奨設定
module.exports = {
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint', // TypeScript専用プラグイン
],
extends: [
'eslint:recommended', // espreeベースのルール(互換性あり)
'plugin:@typescript-eslint/recommended', // TypeScript推奨ルール
],
};
ポイント: eslint:recommendedは espree 向けのルールセットですが、@typescript-eslint/parser でも問題なく動作します。
JavaScript と TypeScript 混在プロジェクト
ファイル拡張子ごとに異なるパーサを適用することも可能です。
javascript// overridesを使った拡張子ごとの設定
module.exports = {
parser: 'espree', // デフォルトはJavaScript用
parserOptions: {
ecmaVersion: 2024,
sourceType: 'module',
},
overrides: [
{
// TypeScriptファイルのみ別パーサを使用
files: ['*.ts', '*.tsx'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
},
plugins: ['@typescript-eslint'],
extends: ['plugin:@typescript-eslint/recommended'],
},
],
};
このアプローチにより、JavaScript ファイルは高速な espree で、TypeScript ファイルは適切な@typescript-eslint/parser で解析されます。
速度最適化の手法
型情報を使わないルールの活用
@typescript-eslint/parser の最も重い処理は、型情報の解析です。型情報が不要なルールのみを使用する場合は、projectオプションを省略できます。
typescript// 型情報を使わない設定(高速)
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2024,
sourceType: 'module',
// project オプションを省略
},
extends: [
'plugin:@typescript-eslint/recommended', // 型情報不要のルールのみ
],
};
この設定により、処理速度が大幅に向上します。
キャッシュの活用
ESLint のキャッシュ機能を有効にすることで、2 回目以降の実行速度が向上します。
bash# キャッシュを有効にしてESLintを実行
yarn eslint --cache --cache-location .eslintcache src/
キャッシュファイルを.gitignoreに追加することをお忘れなく。
text# .gitignore
.eslintcache
以下の図は、パーサ選択とパフォーマンスの関係を示しています。
mermaidflowchart TD
project["プロジェクト"] --> has_ts{"TypeScriptを<br/>使用?"}
has_ts -->|No| use_espree["espree<br/>(最速)"]
has_ts -->|Yes| need_type{"型情報ルールが<br/>必要?"}
need_type -->|No| ts_fast["@typescript-eslint/parser<br/>(project オプションなし)<br/>(速い)"]
need_type -->|Yes| ts_full["@typescript-eslint/parser<br/>(project オプションあり)<br/>(やや遅い)"]
use_espree --> cache["キャッシュ活用で<br/>さらに高速化"]
ts_fast --> cache
ts_full --> cache
この図から、プロジェクトの要件に応じた最適なパーサ構成を選択できます。
具体例
ケース 1: 純粋な JavaScript プロジェクト
React(JavaScript)プロジェクトで espree を使用する例です。
プロジェクト構成
textmy-js-project/
├── src/
│ ├── App.js
│ ├── components/
│ └── utils/
├── package.json
└── .eslintrc.js
パッケージのインストール
bash# ESLintとReact用プラグインをインストール
yarn add -D eslint eslint-plugin-react eslint-plugin-react-hooks
ESLint 設定ファイル
javascript// .eslintrc.js
module.exports = {
env: {
browser: true,
es2024: true,
node: true,
},
extends: [
'eslint:recommended', // espreeのデフォルトルール
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
parserOptions: {
ecmaVersion: 2024,
sourceType: 'module',
ecmaFeatures: {
jsx: true, // JSX構文を有効化
},
},
plugins: ['react', 'react-hooks'],
settings: {
react: {
version: 'detect',
},
},
};
この設定では、espree が暗黙的に使用され、最新の JavaScript 構文と React の JSX を解析します。
サンプルコード検証
javascript// src/App.js
import React, { useState } from 'react';
// ESLintが正しく解析できるJavaScriptコード
function App() {
const [count, setCount] = useState(0);
// espreeは最新のアロー関数、分割代入などを完全にサポート
const handleClick = () => {
setCount((prevCount) => prevCount + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}
export default App;
実行結果
bash# ESLintを実行
yarn eslint src/
# 出力例(問題がない場合)
✨ Done in 0.52s
速度: JavaScript のみのプロジェクトでは、espree が最も高速です。1000 ファイル規模でも数秒で解析が完了します。
ケース 2: TypeScript プロジェクト(型情報なし)
Next.js(TypeScript)プロジェクトで、型情報を使わない軽量な設定例です。
パッケージのインストール
bash# TypeScript ESLint関連パッケージをインストール
yarn add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
yarn add -D eslint-config-next
ESLint 設定(高速版)
javascript// .eslintrc.js
module.exports = {
extends: [
'next/core-web-vitals',
'plugin:@typescript-eslint/recommended', // 型情報不要のルール
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2024,
sourceType: 'module',
// project オプションを省略することで高速化
},
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
},
};
この設定では、型情報を使用しないため、@typescript-eslint/parser でも比較的高速に動作します。
サンプルコード検証
typescript// src/components/Counter.tsx
import React, { useState } from 'react';
// TypeScript特有の型注釈をパーサが正しく解析
interface CounterProps {
initialValue?: number;
}
export const Counter: React.FC<CounterProps> = ({
initialValue = 0,
}) => {
const [count, setCount] = useState<number>(initialValue);
// @typescript-eslint/parserがTypeScript構文を理解
const increment = (): void => {
setCount((prev) => prev + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+1</button>
</div>
);
};
実行とパフォーマンス
bash# ESLintを実行(キャッシュ有効)
yarn eslint --cache src/
# 初回実行
✨ Done in 2.15s
# 2回目以降(キャッシュ使用)
✨ Done in 0.38s
速度: 型情報を使わない場合、espree と比較して約 2〜3 倍の処理時間ですが、十分に実用的な速度です。
ケース 3: TypeScript プロジェクト(型情報あり)
型情報を活用した高度なルールチェックを行う例です。
tsconfig.json の準備
json{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM"],
"jsx": "preserve",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
ESLint 設定(型情報活用版)
javascript// .eslintrc.js
module.exports = {
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking', // 型情報必須
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2024,
sourceType: 'module',
project: './tsconfig.json', // 型情報を読み込む
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint'],
};
recommended-requiring-type-checkingを使うことで、型情報を活用した高度なルールが有効になります。
型情報を活用するルール例
javascript// .eslintrc.jsにルールを追加
module.exports = {
// ... 前述の設定
rules: {
// Promiseの誤用を検出(型情報が必要)
'@typescript-eslint/no-floating-promises': 'error',
// 不要なnullチェックを検出(型情報が必要)
'@typescript-eslint/no-unnecessary-condition': 'warn',
// any型の明示的な使用を検出
'@typescript-eslint/no-explicit-any': 'error',
},
};
サンプルコード検証
typescript// src/services/api.ts
// 型情報を活用したルールが動作するコード例
interface User {
id: number;
name: string;
email: string;
}
class UserService {
// Promiseを返す関数
async fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// 型情報を活用したルールでチェックされる
async processUser(id: number): Promise<void> {
// ❌ エラー: Promiseが適切に処理されていない
// @typescript-eslint/no-floating-promises が検出
// this.fetchUser(id);
// ✅ 正しい: awaitで処理
const user = await this.fetchUser(id);
console.log(user.name);
}
// 不要なnullチェックの例
validateEmail(email: string): boolean {
// ❌ 警告: emailは既にstring型なのでnullチェック不要
// @typescript-eslint/no-unnecessary-condition が検出
// if (email !== null && email.includes('@')) {
// ✅ 正しい
if (email.includes('@')) {
return true;
}
return false;
}
}
これらのルールは、型情報がなければ検出できません。
実行とパフォーマンス比較
bash# 型情報ありで実行
yarn eslint src/
# 処理時間
✨ Done in 5.82s
以下の表は、3 つのケースでの速度比較です。
| # | ケース | パーサ | 型情報 | 1000 ファイルの処理時間(目安) |
|---|---|---|---|---|
| 1 | JavaScript | espree | - | 0.5 秒 |
| 2 | TypeScript | @typescript-eslint/parser | なし | 1.5 秒 |
| 3 | TypeScript | @typescript-eslint/parser | あり | 5.5 秒 |
速度の考察: 型情報を活用する場合、処理時間は増加しますが、高度なバグ検出が可能になります。プロジェクトの規模と要件に応じて選択しましょう。
ケース 4: モノレポでの混在プロジェクト
複数のパッケージを持つモノレポで、JavaScript と TypeScript が混在する例です。
プロジェクト構成
textmonorepo/
├── packages/
│ ├── shared-utils/ # TypeScriptライブラリ
│ │ ├── src/
│ │ ├── tsconfig.json
│ │ └── .eslintrc.js
│ └── web-app/ # JavaScriptアプリ
│ ├── src/
│ └── .eslintrc.js
├── .eslintrc.js # ルート設定
└── package.json
ルート ESLint 設定
javascript// ルート .eslintrc.js
module.exports = {
root: true,
env: {
node: true,
es2024: true,
},
parserOptions: {
ecmaVersion: 2024,
},
extends: ['eslint:recommended'],
};
TypeScript パッケージの設定
javascript// packages/shared-utils/.eslintrc.js
module.exports = {
extends: [
'../../.eslintrc.js', // ルート設定を継承
'plugin:@typescript-eslint/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint'],
};
JavaScript パッケージの設定
javascript// packages/web-app/.eslintrc.js
module.exports = {
extends: [
'../../.eslintrc.js', // ルート設定を継承
'plugin:react/recommended',
],
// parserは明示しない(espreeがデフォルト)
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
plugins: ['react'],
};
モノレポ全体での Lint 実行
bash# ルートディレクトリからすべてのパッケージをLint
yarn eslint packages/*/src/
# または各パッケージで個別に実行
cd packages/shared-utils && yarn eslint src/
cd packages/web-app && yarn eslint src/
この構成により、各パッケージの特性に応じた最適なパーサが自動的に選択されます。
以下の図は、モノレポにおけるパーサの使い分けを示しています。
mermaidflowchart TD
root["モノレポルート<br/>(基本設定)"] --> pkg1["packages/shared-utils<br/>(TypeScript)"]
root --> pkg2["packages/web-app<br/>(JavaScript)"]
pkg1 --> parser1["@typescript-eslint/parser<br/>+ 型情報活用"]
pkg2 --> parser2["espree<br/>(デフォルト)"]
parser1 --> lint1["TypeScript特有の<br/>ルールチェック"]
parser2 --> lint2["JavaScript<br/>ルールチェック"]
まとめ
ESLint の 2 つの主要パーサ、espree と@typescript-eslint/parser について、互換性と速度の観点から解説しました。
パーサ選択の基本原則は以下の通りです。
- JavaScript のみのプロジェクト: espree を使用(最速、デフォルト)
- TypeScript プロジェクト(基本的なチェック): @typescript-eslint/parser を型情報なしで使用(速度と機能のバランス)
- TypeScript プロジェクト(高度なチェック): @typescript-eslint/parser を型情報ありで使用(最も強力、やや低速)
互換性については、@typescript-eslint/parser は JavaScript ファイルも解析できるため、混在プロジェクトでも使用可能です。ただし、ファイル拡張子ごとにoverridesを使って適切なパーサを割り当てることで、最適なパフォーマンスが得られます。
速度最適化のためには、以下の手法が有効です。
- 型情報が不要な場合は
projectオプションを省略する - ESLint のキャッシュ機能(
--cache)を活用する - 必要最小限のルールセットを選択する
- モノレポでは各パッケージに適したパーサを使い分ける
プロジェクトの規模、言語構成、求められる品質レベルに応じて、適切なパーサ設定を選択することで、開発効率とコード品質の両立が可能になります。
関連リンク
articleESLint パーサ比較:espree と @typescript-eslint/parser の互換性と速度
articleESLint が遅い時の処方箋:--cache/並列化/ルール絞り込みの実践
articleESLint の内部構造を覗く:Parser・Scope・Rule・Fixer の連携を図解
articleESLint 運用ダッシュボード:SARIF/Code Scanning で違反推移を可視化
articleESLint シェアラブル設定の設計術:単一ソースで Web/Node/React をカバー
articleESLint Flat Config 速見表:files/ignores/plugins/rules/languageOptions の書き方
articleGrok プロンプト・テンプレ 100 連発:要約/翻訳/コード/分析 早見表
articleGitHub Copilot Workspace と Cursor/Cline の比較検証:仕様駆動の自動化能力はどこまで?
articleGitHub Actions 署名戦略を比べる:SHA ピン留め vs タグ参照 vs バージョン範囲
articlegpt-oss が OOM/VRAM 枯渇で落ちる:モデル分割・ページング・バッチ制御の解決策
articleGPT-5 ツール呼び出しが暴走する時の診断フロー:関数設計/停止条件/リトライ制御
articleGit の index.lock 残留問題を解決:並行実行・クラッシュ後の正しい対処法
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来