# 概要
サバイバルTypeScriptのメモです。
今回の記事では、サバイバルTypeScriptのESlintの章をまとめていきます。
個人的には、学んだことを後から振り返ってわかるようにまとめる「板書」や「ノート」のような感覚で記載しています。
その分読みにくいところなどあるかと思いますが、ご了承ください。🙇♂️
【補足】
この記事のハンズオンの部分は、専用のリポジトリを作成しGitHubにあげています。
専用のリポジトリ
# この章の目的(ゴール)
※これはあくまで、サバイバルTypeScriptの目的(ゴール)です。
TypeScriptをESlintでチェックできるようになること。
# ESLintの設定ファイルを記述
ESLintには、lintチェックの際のオプションなどを設定するための設定ファイル(.eslintrc.js
ファイルなど)が必要になる。
【サンプルファイル】
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
};
### 上記のサンプルファイルのそれぞれのオプションについて
# root
eslint
コマンドを実行したディレクトリを起点に、ディレクトリを遡って、設定ファイルという仕様がeslintには存在します。
例えば、ディレクトリ/a/b/
でeslint
コマンドを実行したとします。その場合、ESLintは次の順番で設定ファイルを探し出します。
① /a/b/.eslintrc.js
② /a/.eslintrc.js
③ /.eslintrc.js
この探索は、ルートディレクトリまで遡ります。
そして、この探索中に複数個の設定ファイルが発見された場合は、全ての設定内容がマージされていきます。
このroot
オプションは、このオプションがtrue
になっている設定ファイルが見つかるとその時点で探索を終了させてくれます。
# env
env
オプションは、チェック対象のJavaScriptやTypeScriptのコードがどの実行環境で使われるコードなのかをESLintに伝えてくれます。
このオプションがあると何が嬉しいかといいますと、ESLintがグローバル変数を認識できるようになります。
例えば、TypeScriptのコードをフロントエンド(ブラウザ)で使うのであれば、env
オプションの中にbrowser: true
とすることで、alert
やwindow
といったグローバル変数をちゃんとグローバル変数として認識してくれます。
他にもサンプルファイルにもあるように、es2021: true
を追加するとES2021までに導入されたグローバル変数が認識されます。
他にもnodeなどの実行環境が指定ができます。(指定可能な実行環境の一覧は公式ドキュメントにあります。)
【補足】
このenv
オプションの設定はESLintのno-undef
ルールに関係します。
といいますのも、フロントエンド側のTypeScriptのコードの中でwindow
などを普通に使ってても、問題なく使用できますし動きます。
がしかし、ブラウザで実行されることを知らないESLintからすると、未定義の変数が使われていると認識するため警告が出てしまうでしょう。
そのため、env
オプションは正しく設定する必要があります。
# parserOptions
parserOptions
はチェック対象のjavascriptのコードがどの構文を使用しているかをESLintに伝えるためのオプションです。
-
ecmaVersion
これは、どのバージョンのECMAScriptを使用するか指定するオプションです。
デフォルトでは、ECMAScript 5が指定されていますが、これは非常に古いバージョンですのでベット指定してあげる必要があります。
また、env
オプションでes2022
のようなECMAScriptのバージョンを指定している場合、ecmaVersionにも自動的にes2022
のようにバージョンが指定されるため、省略が可能です。 -
sourceType
JavaScriptには、
スクリプトモード
とモジュールモード
の二つのモードがあります。
sourceType
オプションは、チェック対象のJavaScriptのコードがどっちのモードで書かれているかをESLintに伝えるためのオプションです。
デフォルトでは、スクリプトモード
が指定されています。
モジュールモード
を指定するとimport / export
構文がサポートされます。
基本的には、モジュールモードを指定します。(sourceType: "module"
)
# ESLintのルールを設定する
ESLintには「ルール(rule)」という概念があり、ルールはチェックの最小単位です。
ルールには、例えば以下のようなものがあります。
-
no-console
: console.logを書いてはならない -
camelcase
: 変数名はキャメルケースにすること -
semi
: 文末セミコロンは省略しない
ESLintでは200を超える数のルールが用意されています。
全てのルールについてはこちらの公式ドキュメントに記載されています。
### 重大度について
ESLintのルールには重大度(severity) という重み付けを設定することができます。
重大度には三つのステータスがあります。
-
off
: ルールを無視し、チェックを行わなくする設定。数値は0
。 -
warn
: 警告は表示させるが、eslint
コマンドの終了コードには影響しません。数値は1
。 -
error
: 発見した問題をエラーとして報告し、終了コードを1にします。数値は2
。
### ルールの書き方
ルール(rule)は設定ファイル(.eslintrc.js
)のrule
フィールドにルール名: 重大度
というキー: バリューの形式で記述します。
rules: {
"no-console": "error",
},
### 個々のルールの細かい設定について
実はESLintの個々のルールの中には、それぞれの細かいルールを設定できるというオプションもあります。
わかりやすいところでいうと、 camelcase
オプションがあります。
これは変数名がキャメルケースかをチェックするルールです。
例えば、変数名にスネークケースを使用したい場合が発生するかもしれません。
というのも、Web APIによってはJSONのキーがスネークケースケースになっていることがあるからです。(例: Railsなどは慣習としてスネークケースを使うことが多い)
そういった場合は、ルール名: [重大度, 設定値]
のような配列の形式で設定することで細かいルールを決めることができます。
次の設定例は、プロパティ名に限ってはキャメルケースを強制しない設定です。
rules: {
"no-console": "error",
camelcase: ["error", { properties: "never" }],
},
# JavaScriptファイルのlintチェックやってみる
【JavaScriptのサンプルコード】
※ linterに引っ掛かるために今回はわざと下記のようなコードを書きました。
no-console
とcamelcase
のオプションが引っ掛かるはずです。
export const hello_world = "Hello World";
console.log(hello_world);
こちらのコードを実際にlintチェックにかけていこうと思います。
下記のコマンドは、srcディレクトリ配下のファイルをチェックさせるためのコマンドです。
npx eslint src
チェック対象のファイルを修正して、上記のコマンドを実行してを繰り返して、lintのコマンドの実行結果に何も表示されなくなれば OKです。
# コードを自動修正する
ESLintのルールの中には、コードを自動的に修正できるというものがあります。
例えば、semi
オプションは文末にセミコロンを付けるか付けないかを定めるルールですが、これは自動修正に対応しています。
ここでは、semi
を使ってESLintの自動修正をためしてみます。
rules: {
"no-console": "error",
camelcase: ["error", { properties: "never" }],
semi: ["error", "always"],
},
このルール設定では、"always"
を指定しています。
これは、文末セミコロンを必須にする設定です。
この"always"
を設定した上で、npx eslint src
コマンドを実行すると、
2 errors and 0 warnings potentially fixable with the `--fix` option.
こんな感じのエラーメッセージが表示されます。
これは、--fix
オプションをコマンドに追加することで、自動修正が可能であることを意味するメッセージです。
下記のコマンドを実行したのちに、チェックの対象ファイルを覗いてみてください。
おそらく;
がなかった箇所に;
が新たについているはずです。
npx eslint src --fix
# Shareable configを導入する
上の方でも説明しましたが、ESLintが用意しているルールは200を越え、非常に多いです。
ルールを一つ一つ確認して導入するのは辛みがあります。
そこで、shareable configを導入してみるのがおすすめです。
shareable configとは、「誰かが設定したルールのプリセット」のことです。
これを導入すると、自分でルールを設定する手間が省けるため、非常に便利です。
有名なsharable configのひとつにESLintの公式が公開しているeslint:recommended
というものがあります。
これは、公式ドキュメントのRulesの一覧でチェックマークがついているルールが一括して有効化されます。
これは公式が提供してるため有名ですが、有効になっているルールが少ないため、実務では物足りなさがあるかもしれません。
### 第3者公開のshareable config
第三者が公開しているshareable configもあり、次にあげるものは結構有名な奴です。
名前 | 作成元 | 準拠するコーディング規約 |
---|---|---|
eslint-config-airbnb | Airbnb | Airbnb JavaScript Style Guide、Airbnb React/JSX Style Guide |
eslint-config-airbnb-base | Airbnb | Airbnb JavaScript Style Guide |
eslint-config-standard | Standard JS | JavaScript Standard Style |
eslint-config-google | Google JavaScript Style Guide |
上のshareable configはコーディング規約に基づいて作成されているため、文書としてのコーディング規約とESLintの設定をセットでプロジェクトに導入できる利点があります。
eslint-config-airbnb-baseを使ってみる
まず、yarnでeslint-config-airbnb-base
をインストールします。
その際に、合わせてeslint-plugin-import
も導入します。
【インストールコマンド】
yarn add -D \
eslint-config-airbnb-base@^15 \
eslint-plugin-import@^2
設定ファイル.eslintrc.jsのrulesを消します。その上で、extends: ["airbnb-base"]
を追加してください。
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
// ココ追加
extends: ["airbnb-base"],
};
これで、shareable configの導入は完了です。
設定ファイルで特定のルールを上書きする
ここでは名前付きエクスポートを使いたいので、このルールをオフにすることで警告されないようにしてみましょう。
ルールを上書きするには、.eslintrc.jsのrulesに"import/prefer-default-export": "off"
を追加します。
extends: ["airbnb-base"],
// rulesフィールドでルールを上書きする
rules: {
"import/prefer-default-export": "off",
},
さらに、文字列リテラルはダブルクォートのほうを使いたいので、rulesにquotes: ["error", "double"]
を追加します。
rules: {
"import/prefer-default-export": "off",
// クォーテーションはダブルクォーテーションに指定
quotes: ["error", "double"],
},
# ルールを部分的に無効化する
.eslintrc.js
に記述したコーディングの規約は良くも悪くも、プロジェクト全体に影響を及ぼします。
しかし、コードを書いているとどうしてもこのコーディング規約を破らないといけないタイミングがあります。
そうした場合、コードの一部分のみについてルールを破ることができます。
// eslint-disable-next-line camelcase
export const hello_world = "Hello World";
上記のサンプルコードのように、eslintのdisableコメントを該当箇所の直前に追加することで、コーディング規約のlintチェックを無効にすることができます。
# TypeScriptをlintする
いよいよ本題のTypeScriptのlintをここから始めていきます。
実際のサバイバルTypeScriptでは、別のプロジェクトを新たに作成していますが、こちらでは先程のプロジェクトを引き続き使っていこうと思います。
# TypeScriptを導入する
TypeScript ESLintを使うにはまず、TypeScript環境を構築しておく必要があります。
まず、typescriptを導入しておいてください。
合わせてNode.jsの型定義@types/node
もインストールしておきます。
この型情報は、.eslintrc.jsなどのNode.js環境で実行されるファイルをESLintでチェックするときに利用されます。
【上記のインストールコマンド】
yarn add -D typescript@^4.6 @types/node@^16
※helloWorld.js
ファイルも、helloWorld.ts
ファイルに拡張子を変更する必要があります。
上記のインストールが完了したら、次にTSコンパイラの諸々の設定を記述するためのtsconfig.jsonファイルを作成・編集していきます。
{
"compilerOptions": {
"outDir": "dist"
},
"include": ["src"]
}
【ちょっと解説】
上記の設定ファイルのoutDir
オプションは、TSC(TypeScriptのコンパイラ)がコンパイルを実行した出力結果をどのディレクトリの配下に置くかを指定するもの。
include
オプションは、コンパイルの対象となるファイルがどのディレクトリにあるかをTSCに伝えるためのもの。
下記のコンパイルコマンドを実行すると、/dist
ディレクトリの配下にhelloWorld.js
というコンパイルの出力結果のファイルが生成されているはず。
コンパイルコマンド
npx tsc
※distディレクトリ配下のコンパイル出力ファイルはgithubにpushする必要がないので、.gitignore
ファイルに追加しておきます。
# TypeScript ESLintを導入する
TypeScriptをESLintにチェックさせるには、ESLint本体とTypeScript ESLintの両方をインストールする必要があります。
こちらでは、先程のJavaScriptをESLintでチェックさせる部分でESLint本体は入っているので、TypeScript ESLintのみインストールしておきます。
インストールコマンド
yarn add -D \
@typescript-eslint/parser@^5 \
@typescript-eslint/eslint-plugin@^5
TypeScript ESLintは二種類のパッケージから成り立ちます。
-
@typescript-eslint/parser
: ESLintにTypeScriptの構文を理解させるためのパッケージ。 -
@typescript-eslint/eslint-plugin
: TypeScript向けのルールをESLintに追加するためのパッケージ。
# TypeScript ESLintにはどんなルールがあるのか?
ESLintの200以上のルールに加えて、TypeScript ESLintを導入すると、100以上のルールが追加されます。
追加されるルールの一覧は、TypeScript ESLintのドキュメントで確認できます。
# TypeScript向けのshareable configを導入する
コーディング規約Airbnb JavaScript Style Guideに準拠したshareable configをインストールします。
ただし今回の場合は、すでにJavaScriptの方はインストールしているのでTypeScriptの方(eslint-config-airbnb-typescript
)を今回はインストールする。
yarn add -D eslint-config-airbnb-typescript@^17
eslint-config-airbnb-base
はJavaScript向けのshareable configです。(上記で登場済み)
これを上書きして、TypeScript ESLintのルールを追加したり、TypeScriptコンパイラがチェックするためESLintでチェックする必要がないルールを除外する設定を加えるのがeslint-config-airbnb-typescript
です。
※eslint-plugin-importは依存関係上、導入が必要なパッケージです。
# TypeScript ESLintの設定ファイルを作る
TypeScript ESLintを動かすためには、次の2つの設定ファイルを作る必要があります。
(※これってeslintrc.jsファイル一つでやってるとことかない?)
tsconfig.eslint.json
eslintrc.js
これらファイルをプロジェクトルートに作成します。
### tsconfig.eslint.jsファイルについて
TypeScript ESLintでは、lintのチェック時に型情報を利用するためにTSコンパイラを使用します。
その際のコンパイラの設定をtsconfig.eslint.jsonファイルに記載します。
コンパイラの具体的な設定については、tsconfig.jsonファイルをextends
で継承しつつ、上書きが必要な部分のみ記載します。
{
// 継承する設定内容が記述されているconfigファイルを指定する
"extends": "./tsconfig.json"
}
今回は、TypeScriptで記述されたスクリプトファイルだけではなく、ESLintの設定ファイル(.eslintrc.js
)ファイル自体もチェックの対象に含めたいと思いますので、allowJs
オプションの追加とinclude
オプションの上書きをします。
{
"extends": "./tsconfig.json",
"compilerOptions": {
"allowJs": true
},
"include": ["src", ".*.js"]
}
allowjs
オプションをture
にすると、*.js
や*.jsx
などの拡張子のファイルも.js
と*.jsx
もコンパイル対象に含まれるようになる。
※ただしTSではないので、型のチェックが行われるとかではなく、トランスパイルの対象となる。
このようにTypeScript ESLintでチェックする対象は、include
オプションに追加していく必要があります。
tsconfig.eslint.jsonが正しく設定されているか、次のコマンドを実行して出力を確認して見ます。
npx tsc --showConfig --project tsconfig.eslint.json
次に、ESLintの設定ファイルを編集していきます。
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
env: {
browser: true,
es2021: true,
},
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
project: "./tsconfig.eslint.json",
tsconfigRootDir: __dirname,
},
ignorePatterns: ["dist"],
extends: [
"airbnb-base",
"airbnb-typescript/base",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
rules: {
"import/prefer-default-export": "off",
"@typescript-eslint/quotes": ["error", "double"],
},
};
上記の設定ファイルのオプションの中で、root
、env
、parserOptions
のecmaVersion
とsourceType
については説明済みですので省略しようと思います。
# parser
module.exports = {
// ...
parser: "@typescript-eslint/parser",
// ...
};
このparserオプションで設定したパーサーを使用して、eslintはJavaScriptコードやTypeScriptコードの構文の解析を行います。
上記のサンプルでは、TypeScriptのパーサーを指定しています。
このパーサーの指定を行わないと、eslintがTypeScriptの構文の解釈ができず、エラーが発生します。
※【補足】
TypeScriptはJavaScriptの構文を拡張した言語です。
なので、このパーサーさえ入れておけば、TypeScriptに限らずJavaScriptのこのパーサーひとつで対応できます。
要するに、このパーサーひとつで、TypeScriptとJavaScriptのファイルどちらもリントできるようになります。
# plugins
module.exports = {
// ...
plugins: ["@typescript-eslint"],
// ...
};
eslintでは、第三者が公開したルールを使うこともできます。
この第三者が作成したルールは、「プラグイン」という形で公開されています。
eslintでは、plugins
というオプションにプラグインを追加していくことで、新たなルールを追加することができます。
上の例では、TypeScript ESLint独自のルールを追加するために、@typescript-eslintを設定しています。
# parseOptions
module.exports = {
// ...
parserOptions: {
// ...
project: "./tsconfig.eslint.json",
tsconfigRootDir: __dirname,
},
// ...
};
上記の設定のサンプルで設定されているproject
とtsconfigRootDir
はTypeScript独自のオプションです。
tsconfigRootDir
はプロジェクトルートの絶対パスを指定します。
project
は、ESLint実行時に使うコンパイラ設定ファイル(今回ならtsconfig.eslint.json
ファイル)をtsconfigRootDirからの相対パスで指定します。
これらの設定は、TypeScript ESLintが型情報を参照するために必要な設定です。
# ignorePatterns
module.exports = {
// ...
ignorePatterns: ["dist"],
// ...
};
ignorePatternsオプションは、eslintのチェックの対象外にするファイルやディレクトリを指定できるオプションです。
基本的には、コンパイルの実行によって生成されるファイルやディレクトリはチェックの対象外にします。
※今回は、コンパイルの実行結果が/dist
ディレクトリ配下に生成されるので、上記のような指定をしています。
# extends
module.exports = {
// ...
extends: [
"airbnb-base", // ①
"airbnb-typescript/base", // ②
"plugin:@typescript-eslint/recommended-requiring-type-checking", // ③
],
// ...
};
extends
はshareable configを使用するためのオプションです。
①は、JavaScript向けのルールです。
これを拡張してTypeScript ESLintのルールにも範囲を広げたのが②です。
※①と②は上の順番でないと正しく設定されないので注意してください。
③はTypeScript ESLintが提供する推奨ルールセットで、型情報を要するルールを含みます。
このルールセットでどのルールが有効になるかは、公式ドキュメントをご覧ください。
# rules
module.exports = {
// ...
rules: {
"import/prefer-default-export": "off",
"@typescript-eslint/quotes": ["error", "double"],
},
// ...
};
最後に、rules
というオプションについてです。
ここのrulesは、shareable configで有効化されたルールを上書きするのに用いています。TypeScript ESLintで追加されたルールは、@typescript-eslint/
が接頭辞になります。
基本的にはrules
の部分に様々なTypeScriptのチェックに関するルールを追加する。
# 最後に
ここまでで、TypeScript ESLintを導入してチェックするための設定が一通り完了です。
最後にnpx eslint .
コマンドでチェックを実行し確認することができます。