12k
All articles

ESLint による TypeScript のリント

TypeScript向けESLint 10のflat config設定。typescript-eslintで構成し、projectServiceで型付きlintを有効化し、Prettierも整合させます。

OpenReplay Team
OpenReplay Team
ESLint による TypeScript のリント

2026年7月時点で、TypeScript をリントする現在の方法は、フラットコンフィグ(eslint.config.mjs)で ESLint 10 と typescript-eslint パッケージを使う構成です。検索結果の多くが今も表示している旧来の .eslintrc 形式ではありません。

2022年のチュートリアルからコンフィグをコピペしたのに、ESLint がそれを完全に無視するのを目の当たりにした経験があるなら、理由はこれです。もはや存在しないコンフィグシステム向けに書かれたものだからです。置き換え後の記述は短いものの、型情報を利用する部分には見落としやすいオプションが1つ必要になります。

ESLint 10 は eslintrc コンフィグシステムを完全に削除しました。これはプロジェクトがフラットコンフィグ移行計画の中で予告していた通りです。この変更ひとつで2024年以前のチュートリアルはほぼすべて機能しなくなります。ESLint が .eslintrc.eslintignore ファイルを一切読み込まなくなったためです。本ガイドでは、TypeScript 向けの正しくコピペ可能なフラットコンフィグを示し、型情報を利用するルールの有効化方法を解説し、リントを npm スクリプト・エディタ・CI に組み込む手順を紹介します。

要点

  • 現代的なスタックは、ESLint 10 と typescript-eslint v8 をフラットコンフィグで組み合わせたもの。ESLint 10 以降、.eslintrc/.eslintignore は完全に廃止された。
  • 最小構成のコンフィグは、eslint/configdefineConfig()js.configs.recommendedtseslint.configs.recommended を渡し、eslint.config.js/.mjs というファイル名で保存する。
  • no-floating-promises のような型情報を利用するルールには parserOptions: { projectService: true } が必要。空の parserOptions では有効にならない。
  • 型付きリントはリント前に TypeScript にプロジェクトのビルドを要求するため速度が落ちる。CI で実行し、エディタでは IDE のキャッシュに任せるとよい。
  • フラットコンフィグでは --ext フラグは不要。対象ファイルの指定は各ブロックの files glob が担うため、リントスクリプトは eslint . だけで済む。

ESLint と TypeScript は同じ仕事をしているのか?

ESLint と TypeScript は競合ではなく補完関係にあります。typescript-eslint の一部のルールはコードをより深く読み解くために TypeScript の型チェッカーを利用しますが、両ツールが答える問いは異なります。TypeScript のコンパイラは型の整合性を検証し、ESLint はコードベース全体にわたってスタイルを強制し、バグになりそうな箇所(未使用変数、放置された Promise、危険なパターンなど)を検出します。両方を実行するのが正解です。

TSLint から移行しようとしている場合、TSLint はすでに何年も前に終了していることに注意してください。開発元は 2019年に非推奨化を発表し、typescript-eslint への移行を推奨しました。その結果、ESLint エコシステムが TypeScript のリントにおける標準となりました。新規プロジェクトで TSLint を選ぶ理由はありません。

インストール前提として1点。ESLint 10 は古い Node バージョンのサポートを打ち切りました。現在の動作要件は Node.js v20.19.0 以上、v22.13.0 以上、または v24 以上で、v21.x と v23.x はサポート対象外です。

TypeScript 向けの ESLint はどう設定するのか?

実際に必要となる4つのパッケージをインストールします。

npm i -D eslint @eslint/js typescript typescript-eslint

typescript-eslint ヘルパーはパーサーとプラグインをまとめて提供するため、@typescript-eslint/parser@typescript-eslint/eslint-plugin を手動で組み合わせる必要はありません。現行メジャーバージョンにも対応しており、typescript-eslint が公開している ESLint の対応範囲^8.57.0 || ^9.0.0 || ^10.0.0 なので、typescript-eslint@latest(v8.x)は ESLint 10 上で問題なく動作します。

eslint.config.mjs を作成します(.eslintrc ではなくフラットコンフィグです)。

// eslint.config.mjs
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';

export default defineConfig(
  js.configs.recommended,
  tseslint.configs.recommended,
);

これで動作するベースラインになります。ESLint コアの推奨ルールに加えて typescript-eslint の推奨セットが適用され、typescript-eslint のパーサーとプラグインも自動的に指定されます。defineConfig() は ESLint コアが提供するヘルパーで、現在はこちらを使うべきです。typescript-eslint は独自の tseslint.config() を非推奨としdefineConfig() への移行を推奨しているためです。旧ヘルパーも引き続き動作するので、すでに動いているコンフィグが壊れることはありませんが、新規セットアップでは defineConfig() を使いましょう。どちらの場合でも tseslint のインポートは残してください。tseslint.configs.* や glob ヘルパーで引き続き必要になります。

より厳格にし、個々のルールを調整する

recommended は出発点にすぎません。さらに厳しくするためのオプトインなプリセットが2つあります。tseslint.configs.strict はより主張の強い正当性チェックのルールを追加し、tseslint.configs.stylistic は型情報を必要としない一貫性のルールを追加します。コンフィグ配列内で recommended と並べて追加してください。

任意のルールは rules ブロックで上書きできます。重大度は3段階ありますoff(または 0)はルールを完全に無効化し、warn(または 1)は終了コードに影響を与えずに問題を報告し、error(または 2)は問題を報告したうえで ESLint を終了コード 1 で終了させます。可視化はしたいがブロックはしたくない項目には warn を、リポジトリに混入してはならない項目には error を使いましょう。後者は非ゼロ終了となり CI を失敗させます。

rules: {
  '@typescript-eslint/no-explicit-any': 'warn',
  '@typescript-eslint/no-unused-vars': 'error',
}

現代的なコンフィグでは、数値形式よりも文字列の重大度('warn'/'error')を推奨します。可読性が高く、数値のみのスタイルは古い .eslintrc チュートリアルの典型的な特徴です。

型情報を利用するリント:型情報が必要なルール

最も価値の高いルールのいくつか、たとえば no-floating-promisesno-misused-promises は型情報を必要とします。これを有効にするには parserOptions: { projectService: true } を追加します。これは typescript-eslint v8 以降、型付きリントを有効にする推奨方法であり、設定量が少なく動作も速いことから、旧来の project オプションを置き換えるものです。あわせて、プリセットも型チェック版(recommendedTypeCheckedstrictTypeCheckedstylisticTypeChecked)に切り替えてください。空の parserOptions: {} では型情報を利用するリントは有効になりません。これはコピーされたコンフィグでよく見られる誤りです。

{
  files: ['**/*.ts', '**/*.tsx'],
  extends: [tseslint.configs.recommendedTypeChecked],
  languageOptions: {
    parserOptions: {
      projectService: true,
      tsconfigRootDir: import.meta.dirname,
    },
  },
}

型付きリントには実コストがあります。これを有効にすると、ESLint がリントを行う前に TypeScript がプロジェクトをビルドする必要があり、小規模なコードベースなら1〜2秒、大規模なものではそれよりはっきりと時間がかかります。typescript-eslint 自身のアドバイスはここでの非対称性を利用しています。エディタのプラグインは型情報をキャッシュするためこのペナルティをほぼ回避できるので、完全な型付きリントは CI とコミット前フックで実行し、日常的な作業はエディタに任せるという方針です。また projectService を使うと、別途 tsconfig.eslint.json を保守するという従来の回避策も不要になります。エディタが使っているのと同じプロジェクトを利用するためです。

JS と TS を分け、無視対象を設定する

型チェック対象のルールは TypeScript が理解できるファイルにのみ意味があります。したがって **/*.ts/**/*.tsx にスコープを限定し、素の JavaScript では無効化してください。typescript-eslint はまさにこのためのプリセットを提供しています。公式ドキュメントでは **/*.js のブロックに tseslint.configs.disableTypeChecked を適用して TypeScript 固有の設定を取り除いています。フラットコンフィグでは、無視設定は ignores キーだけを持つコンフィグブロックであり、これが .eslintignore の代替となります。

// eslint.config.mjs
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
import prettier from 'eslint-config-prettier';

export default defineConfig(
  { ignores: ['dist/', 'node_modules/', 'coverage/', '**/*.d.ts'] },
  js.configs.recommended,
  {
    files: ['**/*.ts', '**/*.tsx'],
    extends: [tseslint.configs.recommendedTypeChecked],
    languageOptions: {
      parserOptions: { projectService: true, tsconfigRootDir: import.meta.dirname },
    },
    rules: { '@typescript-eslint/no-explicit-any': 'warn' },
  },
  { files: ['**/*.js', '**/*.mjs'], extends: [tseslint.configs.disableTypeChecked] },
  prettier, // 必ず最後に置く
);

フォーマットは Prettier に任せ、ワークフローを整える

フォーマットは ESLint の外に出しておきましょう。Prettier と競合する ESLint のスタイル系ルールを無効化するために eslint-config-prettier を最後に追加し、バージョンは ^10.1.8 以降に固定してください。このバージョン指定は重要です。2025年7月、メンテナーの npm 認証情報を狙ったフィッシング攻撃により、4つの改ざんされたリリースが公開されました(CVE-2025-54313 として追跡)。バージョン 8.10.1、9.1.1、10.1.6、10.1.7 には、Windows マシン上で同梱の DLL ペイロードを実行する postinstall スクリプトが含まれており、修正版は 8.10.2、9.1.2、10.1.8 です。影響を受けたのはこの4バージョンのみで、ペイロードが実行されるのは Windows のみだったため、10.1.5 などそれ以前のクリーンなビルドが侵害されたことはありません。eslint-plugin-prettier を使って Prettier を ESLint ルールとして実行することも可能ですが、これは任意です。リントが遅くなりノイズも増えるため、多くのチームは採用していません。

lint スクリプトを追加します。対象ファイルの指定は各コンフィグブロックの files glob が担うため、--ext フラグは不要です。

{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
}

そこからさらに、Husky と lint-staged を使ってコミット前にステージ済みファイルへ eslint --fix を実行し、VS Code では codeActionsOnSave"source.fixAll.eslint": "explicit" を指定して保存時の自動修正を有効にし、CI のステップとして eslint . を実行してルール違反がマージをブロックするようにしましょう。

最後にもう1点、対応しておく価値のあることがあります。ESLint 9 は 2026-08-06 にサポート終了を迎え、以降の更新は提供されません。まだ ESLint 9 を使っているなら、上記のコンフィグは ESLint 10 でもそのまま動作するので、ランタイムをアップグレードして先に進みましょう。まずは最小の2行構成から始め、Promise の安全性に関するルールが必要になったら projectService とあわせて recommendedTypeChecked を追加し、eslint-config-prettier は必ず最後に置いてください。

FAQ

型情報を利用するリントは有効にすべきですか? また、そのコストは?

no-floating-promises や no-misused-promises のように型情報なしでは機能しない、価値の高い正当性チェックのルールを使いたいなら有効にすべきです。コストとしては、ESLint がリント前に TypeScript にプロジェクトのビルドを要求するため、小規模プロジェクトでは無視できる程度ですが、大規模プロジェクトでは体感できるほど遅くなります。多くのチームは完全な型付きリントを CI とコミット前フックで実行し、エディタ上では IDE のキャッシュに任せることで、このペナルティを回避しています。

型付きリントにおける projectService と project の違いは何ですか?

どちらも型付きリントを有効にしますが、typescript-eslint は v8 以降 projectService を推奨しています。エディタがすでに使用している tsconfig.json を再利用するため、設定が簡単でリントも高速だからです。旧来の project オプションは1つ以上の TSConfig ファイルをパスで指定する必要があり、多くのチームは別途 tsconfig.eslint.json を保守せざるを得ませんでした。特別な理由がない限り projectService: true を使ってください。

ESLint のフラットコンフィグで --ext フラグはまだ使えますか?

いいえ、フラットコンフィグでは --ext は不要になりました。対象ファイルの指定は各コンフィグブロックの files glob 内で行います(例:files: ['**/*.ts', '**/*.tsx'])。そのため ESLint はどのファイルをリントすべきかをすでに把握しています。lint スクリプトは拡張子フラグなしの eslint . だけで済みます。いまだに --ext を渡しているスクリプトは、削除された eslintrc システム向けに書かれたフラットコンフィグ以前のチュートリアルからコピーされたものです。

eslint-config-prettier と eslint-plugin-prettier のどちらを使うべきですか?

ほとんどのプロジェクトでは eslint-config-prettier を使ってください。Prettier と競合する ESLint のスタイル系ルールを無効化するだけで、実行時のオーバーヘッドはありません。コンフィグ配列の最後に配置します。eslint-plugin-prettier のアプローチは Prettier を実際のリントルールとして実行するもので、任意かつ低速であり、あらゆるフォーマットの差異をリントエラーとして表面化させます。2025年7月のサプライチェーン事件を避けるため、eslint-config-prettier は 10.1.8 以降に固定してください。

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.