サバイバルTypeScriptの板書メモ

# # 概要
サバイバルTypeScriptのメモです。
今回の記事では、[サバイバルTypeScriptのESlintの章](https://typescriptbook.jp/tutorials/eslint)をまとめていきます。

個人的には、学んだことを後から振り返ってわかるようにまとめる「板書」や「ノート」のような感覚で記載しています。
その分読みにくいところなどあるかと思いますが、ご了承ください。🙇‍♂️

【補足】
この記事のハンズオンの部分は、専用のリポジトリを作成しGitHubにあげています。
[専用のリポジトリ](https://github.com/msy7822-ux/eslint-tutorial)



# # この章の目的（ゴール）
※これはあくまで、サバイバルTypeScriptの目的（ゴール）です。
TypeScriptをESlintでチェックできるようになること。

# # ESLintの設定ファイルを記述
ESLintには、lintチェックの際のオプションなどを設定するための設定ファイル（`.eslintrc.js`ファイルなど）が必要になる。

【サンプルファイル】

```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などの実行環境が指定ができます。（指定可能な実行環境の一覧は[公式ドキュメント](https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments)にあります。）

**【補足】**
この`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を超える数のルールが用意されています。
全てのルールについては[こちらの公式ドキュメント](https://eslint.org/docs/rules/)に記載されています。

### ### 重大度について

ESLintのルールには**重大度(severity)** という重み付けを設定することができます。
重大度には三つのステータスがあります。
1. `off`: ルールを無視し、チェックを行わなくする設定。数値は`0`。
2. `warn`: 警告は表示させるが、`eslint`コマンドの終了コードには影響しません。数値は`1`。
3. `error`: 発見した問題をエラーとして報告し、終了コードを1にします。数値は`2`。

### ### ルールの書き方

ルール（rule）は設定ファイル（`.eslintrc.js`）の`rule`フィールドに`ルール名: 重大度`というキー: バリューの形式で記述します。

```js
rules: {
	"no-console": "error",
},
```

### ### 個々のルールの細かい設定について
実はESLintの個々のルールの中には、それぞれの細かいルールを設定できるというオプションもあります。
わかりやすいところでいうと、 `camelcase`オプションがあります。
これは変数名がキャメルケースかをチェックするルールです。

例えば、変数名にスネークケースを使用したい場合が発生するかもしれません。
というのも、Web APIによってはJSONのキーがスネークケースケースになっていることがあるからです。（例: Railsなどは慣習としてスネークケースを使うことが多い）

そういった場合は、`ルール名: [重大度, 設定値]`のような配列の形式で設定することで細かいルールを決めることができます。
次の設定例は、プロパティ名に限ってはキャメルケースを強制しない設定です。
```js
rules: {
	"no-console": "error",
	camelcase: ["error", { properties: "never" }],
},
```

# # JavaScriptファイルのlintチェックやってみる
【JavaScriptのサンプルコード】
※ linterに引っ掛かるために今回はわざと下記のようなコードを書きました。

`no-console`と`camelcase`のオプションが引っ掛かるはずです。

```js: src/helloWorld.js
export const hello_world = "Hello World";
console.log(hello_world);
```

こちらのコードを実際にlintチェックにかけていこうと思います。
下記のコマンドは、srcディレクトリ配下のファイルをチェックさせるためのコマンドです。
```bash
npx eslint src
```

チェック対象のファイルを修正して、上記のコマンドを実行してを繰り返して、lintのコマンドの実行結果に何も表示されなくなれば OKです。

# # コードを自動修正する
ESLintのルールの中には、コードを自動的に修正できるというものがあります。
例えば、`semi`オプションは文末にセミコロンを付けるか付けないかを定めるルールですが、これは自動修正に対応しています。

ここでは、`semi`を使ってESLintの自動修正をためしてみます。

```js: .eslintrc.js
rules: {
	"no-console": "error",
	camelcase: ["error", { properties: "never" }],
	semi: ["error", "always"],
},
```

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

この`"always"`を設定した上で、`npx eslint src`コマンドを実行すると、
```bash
2 errors and 0 warnings potentially fixable with the `--fix` option.
```

こんな感じのエラーメッセージが表示されます。
これは、`--fix`オプションをコマンドに追加することで、**自動修正が可能**であることを意味するメッセージです。

下記のコマンドを実行したのちに、チェックの対象ファイルを覗いてみてください。
おそらく`;`がなかった箇所に`;`が新たについているはずです。

```bash
npx eslint src --fix
```

# # Shareable configを導入する
上の方でも説明しましたが、ESLintが用意しているルールは200を越え、非常に多いです。
ルールを一つ一つ確認して導入するのは辛みがあります。

そこで、shareable configを導入してみるのがおすすめです。
shareable configとは、「**誰かが設定したルールのプリセット**」のことです。
これを導入すると、自分でルールを設定する手間が省けるため、非常に便利です。

有名なsharable configのひとつにESLintの公式が公開している`eslint:recommended`というものがあります。
これは、[公式ドキュメントのRulesの一覧](https://eslint.org/docs/rules/)でチェックマークがついているルールが一括して有効化されます。
これは公式が提供してるため有名ですが、有効になっているルールが少ないため、実務では物足りなさがあるかもしれません。

### ### 第３者公開の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 | Google JavaScript Style Guide |

上のshareable configはコーディング規約に基づいて作成されているため、文書としてのコーディング規約とESLintの設定をセットでプロジェクトに導入できる利点があります。

#### eslint-config-airbnb-baseを使ってみる
まず、yarnで`eslint-config-airbnb-base`をインストールします。
その際に、合わせて`eslint-plugin-import`も導入します。

【インストールコマンド】
```bash
yarn add -D \
  eslint-config-airbnb-base@^15 \
  eslint-plugin-import@^2
```
設定ファイル.eslintrc.jsのrulesを消します。その上で、`extends: ["airbnb-base"]`を追加してください。

```js: .eslint.js
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"`を追加します。

```js: .eslintec.js
extends: ["airbnb-base"],
// rulesフィールドでルールを上書きする
rules: {
	"import/prefer-default-export": "off",
},
```

さらに、文字列リテラルはダブルクォートのほうを使いたいので、rulesに`quotes: ["error", "double"]`を追加します。
```js: .eslint.js
rules: {
	"import/prefer-default-export": "off",
	// クォーテーションはダブルクォーテーションに指定
	quotes: ["error", "double"],
},
```

# # ルールを部分的に無効化する
`.eslintrc.js`に記述したコーディングの規約は良くも悪くも、プロジェクト全体に影響を及ぼします。

しかし、コードを書いているとどうしてもこのコーディング規約を破らないといけないタイミングがあります。

そうした場合、コードの一部分のみについてルールを破ることができます。
```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でチェックするときに利用**されます。

【上記のインストールコマンド】
```typescript
yarn add -D typescript@^4.6 @types/node@^16
```

※`helloWorld.js`ファイルも、`helloWorld.ts`ファイルに拡張子を変更する必要があります。

上記のインストールが完了したら、次にTSコンパイラの諸々の設定を記述するためのtsconfig.jsonファイルを作成・編集していきます。
```json: tsconfig.json
{
  "compilerOptions": {
    "outDir": "dist"
  },
  "include": ["src"]
}
```

【ちょっと解説】
上記の設定ファイルの`outDir`オプションは、TSC（TypeScriptのコンパイラ）がコンパイルを実行した出力結果をどのディレクトリの配下に置くかを指定するもの。

`include`オプションは、コンパイルの対象となるファイルがどのディレクトリにあるかをTSCに伝えるためのもの。

下記のコンパイルコマンドを実行すると、`/dist`ディレクトリの配下に`helloWorld.js`というコンパイルの出力結果のファイルが生成されているはず。

コンパイルコマンド
```bash
npx tsc
```

※distディレクトリ配下のコンパイル出力ファイルはgithubにpushする必要がないので、`.gitignore`ファイルに追加しておきます。

# # TypeScript ESLintを導入する
TypeScriptをESLintにチェックさせるには、ESLint本体とTypeScript ESLintの両方をインストールする必要があります。

こちらでは、先程のJavaScriptをESLintでチェックさせる部分でESLint本体は入っているので、TypeScript ESLintのみインストールしておきます。

インストールコマンド
```bash
yarn add -D \
  @typescript-eslint/parser@^5 \
  @typescript-eslint/eslint-plugin@^5
```

TypeScript ESLintは二種類のパッケージから成り立ちます。
1. `@typescript-eslint/parser`: ESLintにTypeScriptの構文を理解させるためのパッケージ。
2. `@typescript-eslint/eslint-plugin`: TypeScript向けのルールをESLintに追加するためのパッケージ。


# # TypeScript ESLintにはどんなルールがあるのか？
ESLintの200以上のルールに加えて、TypeScript ESLintを導入すると、100以上のルールが追加されます。
追加されるルールの一覧は、[TypeScript ESLintのドキュメント](https://typescript-eslint.io/rules/)で確認できます。

# # TypeScript向けのshareable configを導入する
コーディング規約Airbnb JavaScript Style Guideに準拠したshareable configをインストールします。

ただし今回の場合は、すでにJavaScriptの方はインストールしているのでTypeScriptの方（`eslint-config-airbnb-typescript`）を今回はインストールする。

```bash
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ファイル一つでやってるとことかない？）

1. `tsconfig.eslint.json`
2. `eslintrc.js`

これらファイルをプロジェクトルートに作成します。

### ### tsconfig.eslint.jsファイルについて
TypeScript ESLintでは、lintのチェック時に型情報を利用するためにTSコンパイラを使用します。
その際のコンパイラの設定をtsconfig.eslint.jsonファイルに記載します。

コンパイラの具体的な設定については、tsconfig.jsonファイルを`extends`で継承しつつ、上書きが必要な部分のみ記載します。

```json: tsconfig.eslint.json
{
	// 継承する設定内容が記述されているconfigファイルを指定する
	"extends": "./tsconfig.json"
}
```

今回は、TypeScriptで記述されたスクリプトファイルだけではなく、ESLintの設定ファイル（`.eslintrc.js`）ファイル自体もチェックの対象に含めたいと思いますので、`allowJs`オプションの追加と`include`オプションの上書きをします。
```json: tsconfig.eslint.json
{
	"extends": "./tsconfig.json",
	"compilerOptions": {
		"allowJs": true
	},
	"include": ["src", ".*.js"]
}
```
`allowjs`オプションを`ture`にすると、`*.js`や`*.jsx`などの拡張子のファイルも`.js`と`*.jsx`もコンパイル対象に含まれるようになる。
**※ただしTSではないので、型のチェックが行われるとかではなく、トランスパイルの対象となる。**

このようにTypeScript ESLintでチェックする対象は、`include`オプションに追加していく必要があります。

tsconfig.eslint.jsonが正しく設定されているか、次のコマンドを実行して出力を確認して見ます。
```bash
npx tsc --showConfig --project tsconfig.eslint.json
```


次に、ESLintの設定ファイルを編集していきます。

```js: eslintrc.js
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
```js: eslintrc.js
module.exports = {
	// ...
	parser: "@typescript-eslint/parser",
	// ...
};
```

このparserオプションで設定したパーサーを使用して、eslintはJavaScriptコードやTypeScriptコードの構文の解析を行います。

上記のサンプルでは、TypeScriptのパーサーを指定しています。

このパーサーの指定を行わないと、**eslintがTypeScriptの構文の解釈ができず、エラーが発生**します。

> ※【補足】
TypeScriptはJavaScriptの構文を拡張した言語です。
なので、このパーサーさえ入れておけば、TypeScriptに限らずJavaScriptのこのパーサーひとつで対応できます。
要するに、このパーサーひとつで、TypeScriptとJavaScriptのファイルどちらもリントできるようになります。

-----------------------------------------------------------------------------

#### # plugins
```js: eslintrc.js
module.exports = {
	// ...
	plugins: ["@typescript-eslint"],
	// ...
};
```

eslintでは、第三者が公開したルールを使うこともできます。
この第三者が作成したルールは、「**プラグイン**」という形で公開されています。

eslintでは、`plugins`というオプションにプラグインを追加していくことで、新たなルールを追加することができます。

上の例では、TypeScript ESLint独自のルールを追加するために、@typescript-eslintを設定しています。

-----------------------------------------------------------------------------

#### # parseOptions
```js: eslintrc.js
module.exports = {
	// ...
	parserOptions: {
		// ...
		project: "./tsconfig.eslint.json",
		tsconfigRootDir: __dirname,
	},
	// ...
};
```

上記の設定のサンプルで設定されている`project`と`tsconfigRootDir`はTypeScript独自のオプションです。

`tsconfigRootDir`はプロジェクトルートの絶対パスを指定します。
`project`は、ESLint実行時に使うコンパイラ設定ファイル（今回なら`tsconfig.eslint.json`ファイル）をtsconfigRootDirからの相対パスで指定します。
これらの設定は、**TypeScript ESLintが型情報を参照するために必要な設定**です。

-----------------------------------------------------------------------------

#### # ignorePatterns
```js: eslintrc.js
module.exports = {
	// ...
	ignorePatterns: ["dist"],
	// ...
};
```

ignorePatternsオプションは、eslintのチェックの対象外にするファイルやディレクトリを指定できるオプションです。

基本的には、コンパイルの実行によって生成されるファイルやディレクトリはチェックの対象外にします。
※今回は、コンパイルの実行結果が`/dist`ディレクトリ配下に生成されるので、上記のような指定をしています。

-----------------------------------------------------------------------------

#### # extends
```js: eslintrc.js
module.exports = {
	// ...
	extends: [
		"airbnb-base", // ①
		"airbnb-typescript/base", // ②
		"plugin:@typescript-eslint/recommended-requiring-type-checking", // ③
	],
	// ...
};
```

`extends`はshareable configを使用するためのオプションです。
①は、JavaScript向けのルールです。
これを拡張してTypeScript ESLintのルールにも範囲を広げたのが②です。

**※①と②は上の順番でないと正しく設定されないので注意してください。**

③はTypeScript ESLintが提供する推奨ルールセットで、型情報を要するルールを含みます。
このルールセットでどのルールが有効になるかは、[公式ドキュメント](https://typescript-eslint.io/rules/)をご覧ください。


-----------------------------------------------------------------------------

#### # rules
```js: eslintrc.js
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 .`コマンドでチェックを実行し確認することができます。