typescript-eslintの導入方法とディレクトリごとにルールを設定する方法
typescript-eslint、たまにしか触らないので毎回0から調べてる気がする(そして毎度詰まる
— chilitreat (@chilitreat) January 8, 2022
メモがてから自分用に使い方をまとめて見る。 少し前まではTypeScript本体やESLintと@typescript-eslintのバージョンを揃えないと一気に設定が壊れる印象だったが最近は安定してそう
検証したバージョン
- npm v6.13.4
- Node.js v10.19.0
- typescript v4.3.5
- eslint v7.32.0
- @typescript-eslint/eslint-plugin v4.29.2
- @typescript-eslint/parser v4.29.2
typescript-eslintはがサポートしているTypeScriptのバージョンは >=3.3.1 <4.6.0(2022/01/09現在)
導入方法
基本的に公式のGet Startedに書いてある通り
Linting your TypeScript Codebase | TypeScript ESLint
インストール
npm install --save-dev eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin
.eslintrc.js の設定
プロジェクトルートに、.eslintrc.js
という名前でファイルを作成。以下をコピー&ペーストする
package.jsonに設定を書くこともできるが、eslintrc.jsに書く方がゴチャらないので好み
module.exports = { root: true, parser: '@typescript-eslint/parser', plugins: [ '@typescript-eslint', ], extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', ], };
ちなみに、eslintrc.js以外にも様々なファイル名(拡張子)が使用可能
JSONでもYAMLでもコメントが書けるのでどれを選ぶかはお好みで
eslintrcの各設定項目の意味を解説する
■ root: true
ESLint実行時、解析されるファイルと同じディレクトリ階層にeslintrcが存在した場合は、そのeslintrcに記載された設定が優先される(後勝ちの設定
root: true
と記載されたeslintrcが見つかるまで子ディレクトリから親ディレクトリへ走査する。途中で見つからない場合は ルートディレクトリまで走査する
プロジェクトルートのeslintrcにroot: true
と記載すると、親ディレクトリ以上は走査しないため意図しない設定のマージが防げる
eslintrcとpackage.jsonが同じ階層にあった場合は、eslintrcが優先され、package.jsonは無効化される
■ parser:
ESLintがTypeScriptの構文を解釈できるように@typescript-eslint/parserを指定する
■ plugins:
インストールしたプラグインを読み込ませるために@typescript-eslintを指定する
■ extends:
予め用意された設定を拡張として読み込む eslint:recommended, plugin:@typescript-eslint/recommended, の二つを記載することで、いい感じに設定された推奨ルールを読み込んでいる
extends の設定方法に色々なパターンがあるが、この記事がとても分かりやすかった
■ 他に設定できること
rules, ignorePatternsなどが設定可能
詳細はこちらを参照 eslint.org
基本的な設定項目
eslint:recommended
で設定されているルール
このページの一番左列に✔︎マークがついている項目
plugin:@typescript-eslint/recommended
で設定されているルール
このページの✅列に✅マークがついている項目
plugin:@typescript-eslint/eslint-recommended
plugin:@typescript-eslint/recommended
の中で extendsされている
この記事でも言及されているように、plugin:@typescript-eslint/recommended
が指定されている場合は、追加でextendsさせる必要は無い
ディレクトリごとにルールを設定する
TypeScriptで書かれたバックエンドアプリケーションを想定
基本的にキャメルケースで統一しつつも、データベースのインタフェースのプロパティ名はスネークケースで定義するeslintrcの設定をする
- `app/**/*.ts` のinterfaceの属性名をキャメルケースに設定する - `app/infrastructure/database/*.ts` のinterfaceのプロパティ名をスネークケースに設定する
命名規則を設定するには、@typescript-eslint/naming-convention
を適用する
typescript-eslint/naming-convention.md at main · typescript-eslint/typescript-eslint · GitHub
しかし@typescript-eslint/naming-convention
のルールだけでは、特定のディレクトリ配下のファイルにだけ別のルールを適用することができない
そのため、
orverrides
を指定してルールを上書きするか- 別のルールを適用したいファイルが存在するディレクトリに、.eslintrcを配置するか のどちらかで解決する必要がある。
今回は前者のorverrides
を指定してルールを上書きする方で解決する
先ほど作成した eslintrc.jsに以下を追記する
... rules: { "@typescript-eslint/naming-convention": [ "error", { 'selector': 'property', 'format': [ 'camelCase' ] } // Group Selectorsの property。classProperty, objectLiteralProperty, typePropertyをキャメルケースで指定する ] }, overrides: [ { "files": [ "app/infrastructure/database/*.ts" ], // 上書き対象のGlobパターン "rules": { "@typescript-eslint/naming-convention": [ "error", { 'selector': 'property', 'format': ['snake_case'] } ] } } ] ...
全てファイルに { 'selector': 'property', 'format': [ 'camelCase' ] }
のルールが適用されて困る場合は、orverridesに解析を無視するGlobパターンを記載すれば良い
... rules: { "@typescript-eslint/naming-convention": [ "error", { 'selector': 'property', 'format': [ 'camelCase' ] } // classProperty, objectLiteralProperty, typePropertyをキャメルケースで指定する(Group Selectors) ] }, overrides: [ { "files": [ "app/infrastructure/database/*.ts" ], "rules": { "@typescript-eslint/naming-convention": [ "error", { 'selector': 'property', 'format': ['snake_case'] } ] } }, // ここ追加 { "files": [ "app/infrastructure/api/*.ts" ], // apiは外部APIの仕様によって様々なので無視する "rules": { "@typescript-eslint/naming-convention": [ "off", { 'selector': 'property', 'format': [ 'camelCase' ] } // rulesに書いたルールを指定する ] } } ] ...
このeslintrcを設置することで、ディレクトリごとに異なるルールが設定可能になった
すでに開発が進んでいるプロジェクトで導入する際は、全ファイルで共通したルールを設定した後、ディレクトリごとにルールを無効化するルールをorveridesに追加し、徐々に無効化したルールを有効化してくと比較的辛くなく導入できるはず
コードレビューで好みをの話をされるとモヤるのでLintを整備して秩序と安寧を作っていきたい