雰囲気で書かないESLintの設定ファイル

# この記事が解決する問題

すでに結構いろんな記事が出回っているのですが、あまり設定ごとのピンポイントな説明記事が見当たらなかったので、
この記事では雰囲気でわかってそうだけど実はあまり良くわかっていないオプションのいくつかを私の独断と偏見で選んで解説します。

# plugins と extends

いちばん大事な設定ですが、実は一番間違えやすい設定でもあります。 `@typescript-eslint/eslint-plugin` を例にすると、たとえば

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

と書くこともあればこう書くこともあります。

```js:.eslintrc.js
module.exports = {
  "extends": ["plugin:@typescript-eslint/recommended"],
}
```

すでに他の記事とかでも詳しい説明が書かれてあるので、ここでそれぞれの違いを端的にいうと

Plugins

- **追加のルールセットを読み込むのに使う**
- `plugins` に追加しただけで**ルールは有効化されない**

Extends

- **Shareable config を適用するのに使う**（例えば `eslint-config-google`, `eslint-config-airbnb`）
- 実際に Shareable config は `plugins` の設定を含めることができるので、`extends` ができることは `plugins` より多い

`"extends": ["plugin:@typescript-eslint/recommended"]` でいうと `@typescript-eslint/eslint-plugin` にある `recommended` shareable config を適用するという意味です。

以下の記事には `plugins`, `extends` に関する詳しい説明があるので、すごく参考になるのでぜひ読んでみてください。

https://blog.ojisan.io/eslint-plugin-and-extend

# env

使える・使えないグローバル変数を定義する設定です。
https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments

```js:.eslintrc.js
module.exports = {
  "env": {
    "browser": true,
    "node": true,
  },
}
```

例えばブラウザの実行環境にしかないグローバル変数 `window` を使いたい場合、 `"browser": true` を設定しないとこんな風に怒られます。
![スクリーンショット 2021-05-29 234903.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57546/d096ee58-2fd4-ebed-c927-5601bd3e90cf.png)

またはテストファイルとかで、Jest を使っているなら `describe` / `it` のグローバル変数を使うはずなので、そんなときは `"jest": true` にすると怒られずに済みます。

# parser

ソースコードから抽象構文木を生成するのに利用するパーサーの指定です。
https://eslint.org/docs/user-guide/configuring/plugins#specifying-parser

普通の JavaScript を書いている場合は特に気にする必要はありませんが、
Vue, TypeScript とか、生の JavaScript の構文じゃないファイルをパースするときにこのオプションを使います。
（React の場合は、JSX 構文はデフォルトのパーサーでパースできるので、特に指定は不要です）

例えば TypeScript でいうと、

```bash
npm install --save-dev @typescript-eslint/parser
```

で `@typescript-eslint/parser` をインストールした上、
https://www.npmjs.com/package/@typescript-eslint/parser
このオプションに `@typescript-eslint/parser` を指定します。

```js:.eslintrc.js
module.exports = {
  "parser": "@typescript-eslint/parser",
}
```

# parserOptions

名前の通り、パーサーに渡すオプションです。
https://eslint.org/docs/user-guide/configuring/language-options#specifying-parser-options

その中のよく見られるオプションを取り上げます

- `ecmaVersion`: 利用する ECMAScript のバージョン。例えばスプレッド構文を使っているなら `6` 以上を指定しないといけません。
- `sourceType`: `"script"`, `"module"` を指定できます。ES module を使ってコードを書いているなら `"module"` を指定します。（というか大体 `"module"` しか使いませんね）
- `ecmaFeatures.jsx`: JSX構文を有効化します。

```js:.eslintrc.js
module.exports = {
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    },
  },
}
```

## parserOptions.ecmaVersion と env の関係

https://eslint.org/docs/user-guide/configuring/language-options#specifying-parser-options
に書かれていますが、例えば ES6 向けの設定をするのに、

```js:.eslintrc.js
{
  "env": { "es6": true },
}
```

を設定したら、暗黙的に

```js:.eslintrc.js
{
  "parserOptions": { "ecmaVersion": 6 }
}
```

も適用されますが、その逆は成立しません。

## parserOptions.ecmaFeatures.jsx

JSX に関して公式ドキュメントには気になる一文があります。

> Please note that supporting JSX syntax is not the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) if you are using React and want React semantics.

React を使う場合は「 JSX をオンにするだけじゃ足りないから [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) を適用してね」的な内容だったんですが、
[plugin:react/recommended の中身](https://github.com/yannickcr/eslint-plugin-react/blob/291acbfd6a2caf3934179683c559bb686ff4dbc7/index.js#L118-L151)を一通り見たけど、ルールが追加されてる以外の違いはないので、具体的に何が違うのかはまだよくわからない。

## その他のオプション

Vue のプロジェクトの場合は [vue-eslint-parser](https://www.npmjs.com/package/vue-eslint-parser) を使っていると思いますが（もしくは [eslint-plugin-vue](https://www.npmjs.com/package/eslint-plugin-vue) で間接的にその parser を使っている）、TypeScript と併用する場合は `parserOptions.parser` に `@typescript-eslint/parser` 設定する必要があります。ESLint の公式ドキュメントにこのオプションの説明がないので、たぶんこれは `parser` が `vue-eslint-parser` の時しか受け取れない独自のオプションってところでしょう。

```js:.eslintrc.js
module.exports = {
  "parser": "vue-eslint-parser",
  "parserOptions": {
    "parser": "@typescript-eslint/parser",
  },
}
```

# overrides

プロジェクト内で `.vue`, `.ts`, `.js` とか複数種類のソースコードが混在していて、それぞれのタイプのファイルに違うパーサー・ルールを設定したい場合に使うオプションです。
https://eslint.org/docs/user-guide/configuring/configuration-files#how-do-overrides-work

例えば `.vue`, `.ts` ファイルが混在する場合は、こんな感じにベースの設定を `.ts` 向けの設定にして、 `overrides` で `.vue` ファイル専用の設定値で上書きすれば実現できます。
（厳密に言えば実は [plugin:@typescript-eslint/recommended](https://github.com/typescript-eslint/typescript-eslint/blob/d4f077473afb04f7c4d377dd87318749632b4404/packages/eslint-plugin/src/configs/eslint-recommended.ts#L7-L33) 内でもこれと同じように `overrides` で `.ts`, `.tsx` ファイルの設定をしている）

```js:.eslintrc.js
module.exports = {
  extends: [
    "plugin:@typescript-eslint/recommended",
  ],
  // By default, without `overrides` section, ESLint will not be applied on
  // non-JavaScript file (*.js).
  // https://eslint.org/docs/user-guide/migrating-to-7.0.0#lint-files-matched-by-overridesfiles-by-default
  overrides: [
    {
      files: ["*.vue"],
      extends: ["plugin:vue/recommended"],
    },
  ],
};
```

もしくは `plugin:@typescript-eslint/recommended` の適用を `overrides` に移して、共通のベースを作らないで、それぞれ専用の設定にします。

```js:.eslintrc.js
module.exports = {
  overrides: [
    {
      files: ["*.vue"],
      extends: ["plugin:vue/recommended"],
    },
    {
      files: ["*.ts"],
      extends: ["plugin:@typescript-eslint/recommended"],
    }
  ],
};
```