メインコンテンツまでスキップ

ESLintでTypeScriptのコーディング規約チェックを自動化しよう

本章では、ESLintイーエスリントを使って、TypeScriptをチェックするためのノウハウをチュートリアル形式で学びます。

本章で学べること

本章では次のことを学んでいただきます。

  • コーディング規約の必要性とコーディング規約の問題点
  • ESLintでJavaScriptやTypeScriptをチェックする方法
  • ESLintのルールの設定のしかた
  • エラーを解消する方法
  • チェックを部分的に無効化する方法
  • VS CodeやJetBrains IDEとESLintを統合する方法

チュートリアルをやり終えると、ご自身のプロジェクトにESLintを導入できるようになったりと、実務で役立つ基本的なスキルが身につくはずです。

本章の流れと読み進め方

本章は次の3部構成です。

本章の前半は座学です。「コーディング規約」や「リンター」が何か知らない方向けに、その背景知識を解説します(背景知識)。すでにコーディング規約やリンターが分かっている方、すぐに手を動かしたい方は、ここは読み飛ばしても構いません。

本章の後半はチュートリアルです。本章のゴールは、TypeScriptをESLintでチェックできるようになることです。しかしながら、ESLintでTypeScriptを扱うのは発展的な用法です。そこで、チュートリアルの流れとしては、まず基礎編として、JavaScriptをESLintで扱う方法を学びます(ESLintでJavaScriptをリントしよう)。その後、TypeScriptをESLintを扱う方法を学んでいただきます(ESLintでTypeScriptをリントしよう)。

章末にはおまけとして次のチュートリアルも用意してあります。関心と余力がある方はこちらもご覧ください。

このチュートリアルに必要なもの

このチュートリアルで必要なものは次のとおりです。

  • Node.js v24以上
  • NPM v11以上 (Node.jsに同梱)

Node.jsの導入については、開発環境の準備をご覧ください。

背景知識

TypeScriptの書き方はさまざま

TypeScriptに限らず、プログラミング言語には文法があります。文法を守って書かれたコードは、エラーなく実行やコンパイルができます。

プログラムは文法さえ守れば、誰が書いても一字一句同じコードになるかというと、そうではありません。たとえば、文字列はシングルクォート、ダブルクォート、バッククォートの3通りで書けます。シングルクォートとダブルクォートは機能上の違いがありません。バッククォートはテンプレートリテラルと言い、文字列リテラルとは仕様が異なります。しかし、次の例のような単純な文字列では、この3つは同じ意味になります。

ts
console.log('OK');
console.log("OK");
console.log(`OK`);
ts
console.log('OK');
console.log("OK");
console.log(`OK`);

この例は、どれを使うか意見が割れるところです。本書独自の調査では、「原則的にどれをもっとも多く使うか?」という問いに対し、シングルクォートが55%ともっとも多く、次にダブルクォートが29%、バッククォートは16%という回答が得られました。(回答数232件)

上でとりあげた例はほんの一例です。意味が同じで書き方が異なる例は、数多くあります。

書き方の違いが問題になることも

書き方の違いが問題なることがあります。たとえば、プログラムを共同で開発する場合です。人によって書き方が異なると、その違いが気になったり驚いたりして、コードの本筋が頭に入ってこないことがあります。インデントの幅が統一されていないと、コードが読みにくくなることもあります。結果的に、書き方に違いがあるとプログラムの保守性を損ねる一因になります。

コーディング規約で書き方を統一

理想は、誰が書いても同じコードになることです。そのためにはどうしたらよいでしょうか。解決策のひとつは、書き方のルールを決めることです。コードの書き方の取り決めは「コーディング規約(coding standards)」と呼ばれます。

コーディング規約では、たとえば、次のようなことを決めます。

  • 変数名はキャメルケースにしましょう。
  • console.logは消しましょう。
  • any型は使わないでください。

このようなルールを取りまとめて規約を作るのですが、実用的な規約に仕上げるにはかなりの労力を要します。実務では、公開されている規約を借りてくるほうが現実的です。

公開されている規約には主に次のものがあります。これらは実際に多くのプロジェクトで利用されています。

コーディング規約をチームのみんなで守れば、書き方を統一しやすくなります。

コーディング規約の問題点

コーディング規約にも問題点があります。

運用の手間は少なくない

開発者ひとりひとりが規約を守れば、コーディング規約は機能します。しかし、ヒューマンエラーは起きるものです。規約を知った上で破る場合もありますが、多いのは知らずに破ってしまうことや、間違えてしまうことです。もしも、規約が守られなければ、規約は形式上のものになってしまいます。そうなると、書き方を統一するという目標は達成できなくなってしまいます。

ヒューマンエラーを防ぐには、コードが規約に準拠しているかを日々点検しなければなりません。しかし、これには多くの労力がかかります。もっと重要な仕事がある中で、点検を行うのは無理な場合もあるかもしれません。規約を正しく運用するには、多くの手間がかかるのです。

コミュニケーション上の心理的な負担が増す

コーディング規約は、何が正しく、何が間違いかを定めます。すると、明らかに誤りと判断できるコードが出てきます。他者が書いたコードの誤りを指摘する場面も出てきます。人の仕事の誤りを指摘するのは難しいものです。想像以上に心理的な負担になります。指摘する側は相手の心象を悪くしないよう、伝え方に苦慮します。指摘される側も、前向きに受け取れない場合もあります。相手との対人関係によっては、指摘することが遠慮される場合もあります。

コーディング規約の自動化

書き方を統一するには、コーディング規約は不可欠です。しかし、運用の手間や心理的な課題もあります。これを解決する手助けとなるのがESLintです。ESLintは、JavaScriptやTypeScriptのコードがコーディング規約に準拠しているかをチェックするツールです。

ESLintは、コマンドひとつでチェックが行なえます。チェックは数秒で完了し、すぐに結果がわかります。そのため、点検の手間がほぼなくなります。

加えて、自動修正機能もあります。コードによっては、ESLintが規約に準じたコードに直せる場合もあります。この機能を利用できる場合は、規約違反箇所を修正する手間もなくせます。

不思議なもので、同じ指摘でも人に言われるより、機械に指摘されたほうが気が楽なものです。ESLintでは機械的に問題を指摘してくれるため、コミュニケーション上の心理的負担も軽減できます。

ESLintを導入すると、開発者は規約の運用や心理的ストレスから解放され、開発などのより重要な仕事に集中できるようになります

学びをシェアする

📝TypeScriptは同じ意味でも異なる書き方が可能
💥チーム開発では書き方の違いが問題になることも…
🤝書き方統一のためにコーディング規約を導入しよう
😵でも、規約には運用の手間や心理的な課題もある
✅この課題はESLintで解決できる!

『サバイバルTypeScript』より

この内容をXにポストする

リンターとは

ESLintは一般的に「リンター(linter)」というジャンルのツールです。リンターは、プログラムを静的に解析し、バグや問題点を発見するツールを言います。リンターを使って、問題点を解析することを「リントする(lint)」と言います。

リント(lint)の由来は紡績です。羊毛や綿花から、繊維をつむぐ際に不要になるホコリのような糸くずをリントと呼びます。紡績ではリントを取り除く工程があり、これにちなんでプログラミングでもリントという名前が使われだしたと言われています。

コンパイラとリンターの違い

コンパイラの本質は、ある言語から別の言語に変換することです。TypeScriptコンパイラの場合は、TypeScriptからJavaScriptへの変換です。

リンターの本質は、プログラムの問題点を指摘することです。言語から言語への変換は行いません。

実際は、TypeScriptコンパイラもプログラムの問題点を報告します。たとえば、コンパイラオプションnoUnusedLocalsを有効にすると、未使用の変数をチェックできます。ESLintにもこれと同等のチェックがあります。こうした点はリンターの機能と重複する部分です。

類似のチェック機能があるものの、両者は得意分野が異なります。TypeScriptコンパイラは型のチェックが充実しています。型の側面から問題点を発見するのが得意です。一方、ESLintはインデントや命名規則などのコーディングスタイルや、どのようなコードを書くべきか避けるべきかの意思決定、セキュリティやパフォーマンスに関する分野でのチェックが充実しています。どちらも相互補完的な関係です。したがって、コンパイラとリンターの両方を導入すると、より幅広いチェックが行えるようになります。

TypeScriptコンパイラとESLintの得意分野の比較
TypeScriptコンパイラESLint
言語から言語への変換
型のチェック
構文チェック
コーディングスタイル
コードの意思決定
セキュリティ
パフォーマンス
学びをシェアする

🧵リンター:コードを静的解析し問題点を指摘するツール。ESLintはリンター。
🔀コンパイラ:静的解析もするが、別言語への変換が主目的。tscはコンパイラ。

⚖️tscとESLintの相違点
・tsc:型のチェックが得意
・ESLint:コーディング規約のチェックが得意

『サバイバルTypeScript』より

この内容をXにポストする

ESLintはJavaScriptとTypeScriptの両方をリントできる

元々ESLintはJavaScriptをリントするために作られ、現在もコアがサポートしているのはJavaScriptのみです。ESLintは「プラグイン」という機能拡張を行える仕組みがあり、これを利用してTypeScriptもリントできるようになっています。

プロジェクトを作成する

ここからはESLintの導入方法や使い方をチュートリアル形式で説明していきます。ぜひお手元の環境で実際にトライしてみてください。

まず、このチュートリアルに使うプロジェクトを作成します。

shell
mkdir eslint-tutorial
cd eslint-tutorial
shell
mkdir eslint-tutorial
cd eslint-tutorial

プロジェクトルートにpackage.jsonを作ってください。その内容は次のようにします。

package.json
json
{
"name": "eslint-tutorial",
"license": "UNLICENSED",
"type": "module"
}
package.json
json
{
"name": "eslint-tutorial",
"license": "UNLICENSED",
"type": "module"
}

さらに、TypeScriptをインストールし、TypeScriptの設定ファイルtsconfig.jsonを作成します。

shell
npm install -D typescript
shell
npm install -D typescript
tsconfig.json
json
{
"compilerOptions": {
"target": "esnext",
"moduleResolution": "bundler",
"strict": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"skipLibCheck": true
}
}
tsconfig.json
json
{
"compilerOptions": {
"target": "esnext",
"moduleResolution": "bundler",
"strict": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"skipLibCheck": true
}
}

ESLintの設定ファイルは従来、JavaScriptで書く必要がありましたが、最新のESLintではTypeScriptで書くこともでき、このチュートリアルでもTypeScriptで書いていきます。しかしながら、ESLintのTypeScriptの設定ファイル対応が完全ではない問題が残っています。それを解消するためjitiをインストールしておきます。

shell
npm install -D jiti
shell
npm install -D jiti

ESLintを導入する

次のコマンドを実行してESLintをインストールしましょう。

shell
npm init -y @eslint/config@latest
shell
npm init -y @eslint/config@latest
備考

Next.jsは最初からESLintが導入されています。実務でNext.jsプロジェクトでESLintを使う場合は、導入ステップは省略できます。

上のコマンドを実行すると、ESLintの構成について質問されます。次のように答えを選択してください。

> npx
> "create-config"

@eslint/create-config: v1.11.0

 What do you want to lint? · javascript
 How would you like to use ESLint? · problems
 What type of modules does your project use? · esm
 Which framework does your project use? · none  None of theseを選択してください 
 Does your project use TypeScript? · No / Yes  Yesを選択してください 
 Where does your code run? · browser
 Which language do you want your configuration file be written in? · ts  TypeScriptを選択してください 
 The config that you've selected requires the following dependencies:`

eslint, @eslint/js, globals, typescript-eslint
 Would you like to install them now? · No / Yes
 Which package manager do you want to use? · npm
☕️Installing...

up to date, audited 226 packages in 545ms

116 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
 Successfully created /path/to/eslint-tutorial/eslint.config.ts file.

ESLintが正しくインストールされたか、バージョンを表示して確認してください。

shell
npx eslint -v
v9.39.2
shell
npx eslint -v
v9.39.2

ちなみにこのnpxコマンドは、Nodeモジュール(ライブラリ)の実行ファイルを起動するツールです。npx eslintを実行すると、./node_modules/.bin/eslintが実行されます。

コマンドが完了すると、次のようなディレクトリ構造になっているはずです。

完了後のディレクトリ構造
text
.
├── eslint.config.ts
├── node_modules/
├── package-lock.json
├── package.json
└── tsconfig.json
完了後のディレクトリ構造
text
.
├── eslint.config.ts
├── node_modules/
├── package-lock.json
├── package.json
└── tsconfig.json

eslint.config.tsは、ESLintの設定ファイルです。このファイルには、ESLintのルールを設定します。設定ファイルの内容は次のようになっているはずです。(見やすさのため、改行やインデントを調整しています)

eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
]);
eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
]);

ESLintでJavaScriptをリントしよう

まずは、ESLintを使ってJavaScriptの言語仕様の範囲でリントを試していきましょう。TypeScriptの言語仕様である型注釈やTypeScriptの型情報を使わない範囲でのリントを試していきます。

ESLintのルールを設定する

ESLintには「ルール(rule)」という概念があります。ルールはチェックの最小単位です。たとえば、ルールには次のようなものがあります。

  • no-console: console.logを書いてはならない
  • camelcase: 変数名はキャメルケースにすること

ESLintには200を超えるルールがあります。全ルールのリストは公式ドキュメントにあります。

ESLintでは、複数のルールを組み合わせてコーディング規約を組み立てていきます。

ルールには、重大度(severity)という重み付けが設定できます。重大度は、offwarnerrorの3種類です。offはルールを無効化し、チェックを行わなくする設定です。warnは発見した問題を警告として報告します。報告はするものの、eslintコマンドの終了コードには影響しません。errorは発見した問題をエラーとして報告し、終了コードを1にする効果があります。それぞれの重大度は、0から2までの数値で設定することもできます。

ESLintの重大度
重大度数値効果
off0ルールをオフにする
warn1警告するが終了コードに影響しない
error2警告し、終了コードを1にする

ルールは設定ファイルのrulesフィールドに、ルール名: 重大度のキーバリュー形式で書きます。まずは、no-consoleをルールに追加してみましょう。

eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
{
rules: {
"no-console": "warn",
},
},
]);
eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
{
rules: {
"no-console": "warn",
},
},
]);

ルールによっては、細かく設定できるものもあります。たとえば、camelcaseです。これは変数名がキャメルケースかをチェックするルールです。変数の種類によっては、キャメルケース以外が使いたい場合があります。たとえば、プロパティ名はアンダースコアを使いたいことがあるかもしれません。ウェブAPIによっては、JSONオブジェクトがスネークケース(foo_barのようなアンダースコア区切り)を採用している場合があるからです。この場合、ルール名: [重大度, 設定値]のような配列形式で設定することで、細かいルール設定ができます。次の例は、プロパティ名に限ってはキャメルケースを強制しない設定です。試しに、この設定を加えてみましょう。

eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
{
rules: {
"no-console": "warn",
camelcase: ["warn", { properties: "never" }],
},
},
]);
eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
{
rules: {
"no-console": "warn",
camelcase: ["warn", { properties: "never" }],
},
},
]);
ここまでのふりかえり
  • package.jsonを作りました。
  • eslintをインストールしました。
  • 設定ファイルに次のルールを追加しました。
    • no-console: console.logをコードに残しておいてはいけない。
    • camelcase: 変数名はキャメルケースにすること(プロパティ名を除く)。

コードをチェックする

設定ファイルが準備できたので、コードを作り、ESLintでチェックしてみましょう。

srcディレクトリを作成し、その中にファイルhello-world.tsを作ってください。hello-world.tsの内容は次のようにします。ファイルとしてはTypeScriptですが、まずはJavaScriptの構文の範囲でESLintを貯めすため、JavaScriptのコードとしても読み込めるようにしておきます。

src/hello-world.ts
ts
export const hello_world = "Hello World";
console.log(hello_world);
src/hello-world.ts
ts
export const hello_world = "Hello World";
console.log(hello_world);

hello-world.tsが加わったディレクトリ構造が、次のようになっているか確認してください。

txt
.
├── eslint.config.ts
├── node_modules/
├── package-lock.json
├── package.json
├── src
│   └── hello-world.ts
└── tsconfig.json
txt
.
├── eslint.config.ts
├── node_modules/
├── package-lock.json
├── package.json
├── src
│   └── hello-world.ts
└── tsconfig.json

このhello-world.tsは、わざとコーディング規約に違反するコードになっています。1行目の変数hello_worldはキャメルケースになっていません。2行目では、使ってはいけないconsole.logが使われています。

では、ESLintでチェックを実行してみましょう。チェックは、eslintコマンドを起動するだけです。

ESLintでチェックする
shell
npx eslint
ESLintでチェックする
shell
npx eslint

これを実行すると、次の出力が表示されます。

/path/to/eslint-tutorial/src/hello-world.ts
  1:14  warning  Identifier 'hello_world' is not in camel case  camelcase
  2:1   warning  Unexpected console statement                   no-console

✖ 2 problems (0 error, 2 warnings)

結果の読み方

チェックした結果、問題点が見つかると表形式で詳細が表示されます。各行は4つの列からなります。左から順に、コードの行番号列番号、重大度、問題点の説明、ルール名です。

  ╭── 行番号と列番号
       ╭── 重大度
  1:14  warning  Identifier 'hello_world' is not in camel case  camelcase
  2:1   warning  Unexpected console statement                   no-console
                                                               ╰── ルール名
                 ╰── 問題点の説明

結果に表示されている内容だけでは、どうして問題点になっているのか、どう直したらいいのかが分からないことがあります。その場合は、ルール名からESLintのドキュメントでルールの詳細を調べます。たとえば、上の結果ではルール名にno-consoleが挙がっていますが、この文字列をもとにルールの詳細を探します。no-consoleの詳細ページは、https://eslint.org/docs/rules/no-consoleにあります。

コードを修正してエラーを解消する

src/hello-world.ts
ts
export const hello_world = "Hello World";
console.log(hello_world);
src/hello-world.ts
ts
export const hello_world = "Hello World";
console.log(hello_world);

上のコードをESLintでチェックした結果、2つの問題点が指摘されました。

  • 1行目: 変数名hello_worldがキャメルケースではない
  • 2行目: console.logは使ってはいけない

このエラーを解消したいので、hello-world.tsを編集してみましょう。変数名hello_worldhelloWorldに変更します。2行目のconsole.logは削除しましょう。修正後のコードは次のようになります。

src/hello-world.ts
ts
export const helloWorld = "Hello World";
src/hello-world.ts
ts
export const helloWorld = "Hello World";

再びESLintでチェックして、もう問題がなくなっているか確認してみましょう。

shell
npx eslint
shell
npx eslint

この実行結果に何も出力されなければ、問題点が解消されています。

コードを自動修正する

ESLintのルールの中には、コードの自動修正ができるものがあります。たとえば、ESLint公式が提供しているESLint Stylisticプラグインのsemiルールがあります。これは、文末セミコロンをつけるつけないを定めるルールで、これは自動修正に対応しています。ここでは、semiを使ってESLintの自動修正をためしてみましょう。

まず、ESLint Stylisticプラグインをインストールします。

shell
npm install -D @stylistic/eslint-plugin
shell
npm install -D @stylistic/eslint-plugin

まず、設定ファイルeslint.config.tsrulessemiを追加します。

eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
import stylistic from "@stylistic/eslint-plugin"; // この行を追加
export default defineConfig([
// 次の要素を追加
{
plugins: {
"@stylistic": stylistic,
},
},
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
{
rules: {
"no-console": "warn",
camelcase: ["warn", { properties: "never" }],
"@stylistic/semi": ["warn", "always"], // この行を追加
},
},
]);
eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
import stylistic from "@stylistic/eslint-plugin"; // この行を追加
export default defineConfig([
// 次の要素を追加
{
plugins: {
"@stylistic": stylistic,
},
},
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
{
rules: {
"no-console": "warn",
camelcase: ["warn", { properties: "never" }],
"@stylistic/semi": ["warn", "always"], // この行を追加
},
},
]);

このルール設定では、"always"を指定しています。これは、文末セミコロンを必須にする設定です。

つぎに、hello-world.tsのコードのセミコロンを消して保存してください。

src/hello-world.ts
ts
export const helloWorld = "Hello World"
src/hello-world.ts
ts
export const helloWorld = "Hello World"

自動修正の前にチェックだけを実行し、semiについての問題が報告されるか確認します。

shell
npx eslint
shell
npx eslint

次のような結果が表示されれば、追加したsemiルールが効いていることになります。

/path/to/eslint-tutorial/src/hello-world.ts
  1:40  warning  Missing semicolon  @stylistic/semi

✖ 1 problem (0 errors, 1 warning)
  0 errors and 1 warning potentially fixable with the `--fix` option.

ESLintでコードを自動修正するには、eslintコマンドに--fixオプションをつけます。次のコマンドを実行し、自動修正してみましょう。

shell
npx eslint --fix
shell
npx eslint --fix

自動修正が成功していれば、出力は何も表示されずに処理が終了します。自動修正が効いているかを確認するために、hello-world.tsを開いてみてください。文末にセミコロンが追加されているでしょうか。追加されていれば自動修正成功です。

ここまでのふりかえり
  • src/hello-world.tsを作りました。
  • npx eslintを実行し、srcディレクトリをチェックしてみました。
  • コードを手直しして、ESLintのチェックを通過する流れを体験しました。(camelcase, no-console)
  • npx eslint --fixを実行し、ESLintの自動修正機能を試しました。(semi)

ESLintにはどんなルールがある?

ここまでのチュートリアルでは3つのルールを扱いました(camelcaseno-consolesemi)。ESLintにはもっと多くのルールがあります。ルール数は200を超えます。

ルールの一覧は、公式ドキュメントのRulesESLint Stylisticプラグインのルール一覧で確認できます。一覧では、どのルールが自動修正に対応しているかも確認できます。

ルールを部分的に無効化する

eslint.config.tsで設定した規約はプロジェクト全体に及びます。コードを書いていると、どうしても規約を破らざるをえない部分が出てくることがあります。その場合は、コードのいち部分について、ルールを無効化することもできます。

部分的にルールを無効にするには、その行の前にコメントeslint-disable-next-lineを追加します。たとえば、次の例ように書いておくと、変数名hello_worldがキャメルケースでなくても、ESLintは警告を出さなくできます。

ts
// eslint-disable-next-line camelcase
export const hello_world = "Hello World";
ts
// eslint-disable-next-line camelcase
export const hello_world = "Hello World";

この方法はいざというときに知っておくとよいというものです。ルール無効化コメントだらけになってしまうと本末転倒です。節度を持って使うのが望ましいです。

ESLintでTypeScriptをリントしよう

ここまでのチュートリアルでは、JavaScriptの文法の範疇でESLintをかける方法を学んできました。ここからは、TypeScriptの文法や型システムにまで範囲を広げてESLintを使う方法を学んでいきます。

そもそもESLintでは、TypeScriptはチェックできません。これを補うのがTypeScript ESLintです。これは、上のESLint導入ウィザードで導入済みなので、追加でインストールする必要はありません。

また、eslint.config.tsもすでに次のようにTypeScript ESLintの設定が追加済みであるはずなので、設定の変更も必要ありません。

eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint"; // TypeScript ESLintをインポート
import { defineConfig } from "eslint/config";
import stylistic from "@stylistic/eslint-plugin";
export default defineConfig([
{
plugins: {
"@stylistic": stylistic,
},
},
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended, // TypeScript ESLintの有効化
{
rules: {
"no-console": "warn",
camelcase: ["warn", { properties: "never" }],
"@stylistic/semi": ["warn", "always"],
},
},
]);
eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint"; // TypeScript ESLintをインポート
import { defineConfig } from "eslint/config";
import stylistic from "@stylistic/eslint-plugin";
export default defineConfig([
{
plugins: {
"@stylistic": stylistic,
},
},
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended, // TypeScript ESLintの有効化
{
rules: {
"no-console": "warn",
camelcase: ["warn", { properties: "never" }],
"@stylistic/semi": ["warn", "always"],
},
},
]);

TypeScript ESLintにはどんなルールがある?

TypeScript ESLintを導入すると、100以上のルールが追加されます。追加されるルールの一覧は、TypeScript ESLintのドキュメントで確認できます。

TypeScriptをチェックする

すでに、TypeScript ESLintが有効化されているので、さっそくTypeScriptをチェックしてみましょう。

TypeScriptにはany型という特殊な型があります。これは、どんな型でも代入を許す反面、型チェックを行わないため、安全なコードを書くためには避けたい型です。anyの禁止はTypeScriptコンパイラでは強制できないため、TypeScript ESLintで取り扱うチェックとしてぴったりのトピックです。

📄️ any型

TypeScriptのany型は、どんな型でも代入を許す型です。プリミティブ型であれオブジェクトであれ何を代入してもエラーになりません。

では、hello-world.tshelloWorld変数にany型を指定して、ESLintでチェックしてみましょう。

src/hello-world.ts
ts
export const helloWorld: any = "Hello World";
src/hello-world.ts
ts
export const helloWorld: any = "Hello World";

そうしたら、ESLintを実行してみましょう。

shell
npx eslint
shell
npx eslint

すると、次の結果が出力されるはずです。

/path/to/eslint-tutorial/src/hello-world.ts
  1:26  error  Unexpected any. Specify a different type  @typescript-eslint/no-explicit-any

✖ 1 problem (1 error, 0 warnings)

出力にあるとおり、any型が使われていることを警告してくれています。

型情報をチェックに活用しよう

TypeScript ESLintのルールは主に2種類に分類されます。ひとつは、TypeScriptの構文情報だけでチェックできるルールです。もうひとつは、TypeScriptの型情報をチェックに活用するルールです。上で試したno-explicit-anyルールは、構文情報だけでチェックできるルールでした。

たとえば、次のコードはCの分岐が欠けていて問題のあるコードです。こうした問題はTypeScriptコンパイラでは発見できません。また、構文情報だけに頼ったチェックではChoice型がどんな値を取りうるのか不明なため、問題が見つけられません。

ts
type Choice = "A" | "B" | "C";
 
export function func(choice: Choice) {
switch (choice) {
case "A":
break;
case "B":
break;
}
}
ts
type Choice = "A" | "B" | "C";
 
export function func(choice: Choice) {
switch (choice) {
case "A":
break;
case "B":
break;
}
}

こういった場面では、型情報をチェックに活用するルールが役立ちます。TypeScript ESLintのswitch-exhaustiveness-checkルールは、型情報をチェックに活用するルールの一例です。これは、型情報を参照しながら、switch文の分岐が網羅されているかをチェックするルールです。

では、実際に上のコードをswitch-exhaustiveness-checkルールでチェックしてみましょう。

型情報のルール群を有効化するには、eslint.config.tsに次のように設定を追加します。具体的には、languageOptionsparserOptions.projectService=trueを追加します。加えて、recommendedTypeCheckedも追加しておくと、型情報のルールのうちTypeScript ESLintが推奨するものが有効化されます。最後に、recommendedTypeCheckedに含まれていないswitch-exhaustiveness-checkルールを有効化します。

eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
import stylistic from "@stylistic/eslint-plugin";
export default defineConfig([
{
plugins: {
"@stylistic": stylistic,
},
},
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: {
globals: globals.browser,
parserOptions: { projectService: true },
},
},
tseslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
rules: {
"no-console": "warn",
camelcase: ["warn", { properties: "never" }],
"@stylistic/semi": ["warn", "always"],
"@typescript-eslint/switch-exhaustiveness-check": "warn",
},
},
]);
eslint.config.ts
ts
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
import stylistic from "@stylistic/eslint-plugin";
export default defineConfig([
{
plugins: {
"@stylistic": stylistic,
},
},
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: {
globals: globals.browser,
parserOptions: { projectService: true },
},
},
tseslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
{
rules: {
"no-console": "warn",
camelcase: ["warn", { properties: "never" }],
"@stylistic/semi": ["warn", "always"],
"@typescript-eslint/switch-exhaustiveness-check": "warn",
},
},
]);

hello-world.tsを次のように変更して、ESLintを実行してみましょう。

src/hello-world.ts
ts
type Choice = "A" | "B" | "C";
 
export function func(choice: Choice) {
switch (choice) {
case "A":
break;
case "B":
break;
}
}
src/hello-world.ts
ts
type Choice = "A" | "B" | "C";
 
export function func(choice: Choice) {
switch (choice) {
case "A":
break;
case "B":
break;
}
}

npx eslintの結果は次のようになるはずです。

/path/to/eslint-tutorial/src/hello-world.ts
  4:11  warning  Switch is not exhaustive. Cases not matched: "C"  @typescript-eslint/switch-exhaustiveness-check

✖ 1 problem (0 errors, 1 warning)

switch-exhaustiveness-checkルールでCの分岐が欠けていることを警告してくれています。

以上で、ESLintでTypeScriptをリントするチュートリアルは終わりです。

VS CodeとESLintを統合しよう

備考

このステップはVS Codeを使っている方向けの内容です。WebStormなどのJetBrains IDEを使っている方は、JetBrains IDEとESLintを統合しようを参照してください。これからVS Codeを導入する方は、VS Codeの公式サイトからダウンロードしてください。

ここでは、Visual Studio Code(VS Code)に、ESLintを組み込む方法を説明します。

ESLintはコマンドひとつでコーディング規約をチェックできるようになり、それだけでも便利です。しかし、VS CodeとESLintを統合するとさらに便利になります。コードを書いているときに、リアルタイムで問題点のフィードバックが得られるようになるからです。

ESLintのエラーがVS Codeに表示される様子

VS CodeとESLintを統合するには、ESLintの拡張をVisual Studio Codeのマーケットプレイスからインストールするだけです。

JetBrains IDEとESLintを統合しよう

備考

このステップはJetBrains IDE(WebStorm、IntelliJ IDEA、PyCharmなど)を使っている方向けの内容です。VS Codeを使っている方は、VS CodeとESLintを統合しようを参照してください。

ここでは、WebStormなどのJetBrains IDEに、ESLintを組み込む方法を説明します。

ESLintはコマンドひとつでコーディング規約をチェックできるようになり、それだけでも便利です。しかし、JetBrains IDEとESLintを統合するとさらに便利になります。コードを書いているときに、リアルタイムで問題点のフィードバックが得られるようになるからです。

ESLintのエラーがWebStormに表示される様子

WebStormは、ESLint統合機能がデフォルトで入っているので、プラグインなどをインストールする必要はありません。ESLintを有効にするには、「Preferences」を開き、検索に「eslint」と入力します(①)。絞り込まれたメニューから「ESLint」を開きます(②)。「Automatic ESLint configuration」にチェックを入れます(③)。最後に「OK」を押すと設定完了です(④)。