IntelliJ IDEAでTypeScriptプロダクトを開発するとき、ESLintを導入する方法をまとめてみました。

Table of Contents

はじめに

環境

項目 バージョン
OS Windows10
TypeScript 3.8.3
IntelliJ IDEA 2019.3.3 Ultimate Edition
ESLint 6.8.0
typescript-eslint/parser 2.25.0
typescript-eslint/eslint-plugin 2.25.0
Prettier 2.0.2

前提知識

本記事で登場する以下の基本知識がある読者を対象とします。

  • TypeScript
  • IntelliJ IDEA
  • ESLint
  • Prettier

プロジェクトの作成

TypeScriptのNode.jsプロジェクトを作成します。

npm init -y
npm i -D typescript prettier
npx tsc --init

index.tsを作成します。

const hello: string = "ハロー"
console.log(hello)

実行してハローと表示されればOKです。

npx tsc && node .

ESLintの適応

typescript-eslintを使います。

TSLintは使えないのか?

2019年で非推奨になっています。

Palantir, the backers behind TSLint announced in 2019 that they would be deprecating TSLint in favor of supporting typescript-eslint in order to benefit the community.

typescript-eslint/typescript-eslint README

インストール

Getting Startedを見ます。

npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin

設定ファイルの作成

.eslintrc.jsを作成します。

module.exports = {
  root: true,
  // ESLintにTypeScript syntaxを理解させる
  parser: '@typescript-eslint/parser',
  // 利用するプラグインを指定
  plugins: [
    // ESLintをTypeScriptで使うためのプラグイン
    '@typescript-eslint',
  ],
  // 利用するベース設定を指定
  extends: [
    // ESLintが提供する推奨設定
    'eslint:recommended',
    // ↑の中でTypeScriptに不要なものをOFFにする設定 (TypeScriptの型チェックで事足りているもの)
    // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/configs/eslint-recommended.ts
    'plugin:@typescript-eslint/eslint-recommended',
    // TypeScriptで推奨されるものをONにする設定
    'plugin:@typescript-eslint/recommended',
  ],
};
バージョンについて

@typescript-eslint/parser@typescript-eslint/eslint-pluginは同じバージョンにしてください。

無視ファイルの作成

.eslintignoreを作成します。

node_modules
dist
coverage
distとcoverageについて
今回のサンプルプロジェクトには存在しないディレクトリですが、大抵の場合は必要になります。

動作確認

拡張子.tsを指定して実行します。
2つ以上を指定する場合は.ts,.jsのようにカンマで区切ります。

$ npx eslint . --ext .ts
...
  1:7  error  Type string trivially inferred from a string literal, remove type annotation  @typescript-eslint/no-inferrable-types

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

エラーが出ればOKです。
次のセクションでエラーとの向き合い方を説明します。

Lintエラーに対するアクション

Linterが出すLintエラーとの向き合い方を解説します。

ルールを確認する

typescript-eslintのルールは以下にまとまっています。
まずは、エラーや警告が表示された理由を確認しましょう。

Type string trivially inferred from a string literal, remove type annotation

文字リテラルで初期化していることからstring型であることは自明なため、型注釈を削除してほしい というエラーです。
上記ページ内を@typescript-eslint/no-inferrable-typesで検索すると以下がヒットします。

Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean

number型、string型、boolean型の初期化されている変数は明示的な型注釈を許さない..ということです。

ルールを変更する

ESLintのドキュメントでルールの設定方法を見てみましょう。

.eslintrc.jsrulesに以下を設定できます。

  • ルール名
  • エラーレベル
    • off / warn / error
  • 設定値

たとえば、今回のエラーレベルを警告に変更したい場合は以下のようにします。

module.exports = {
  // ...中略
  rules: {
    "@typescript-eslint/no-inferrable-types": ["warn"]
  }
}

以下のようにエラーが警告に変わりました。

$ npx eslint . --ext .ts
C:\Users\syoum\works\sandbox\typescript\intellij-eslint-prettier\index.ts
  1:7  warning  Type string trivially inferred from a string literal, remove type annotation  @typescript-eslint/no-infer
rable-types

✖ 1 problem (0 errors, 1 warning)
  0 errors and 1 warning potentially fixable with the `--fix` option.
エラーレベルの変更だけを設定したい場合

糖衣構文として、値を配列でなく文字列で指定できます。

  rules: {
    "@typescript-eslint/no-inferrable-types": "warn"
  }

エラーレベル以外の引数を受けつける場合は、公式ページの説明や例を参考にしましょう。
以下はインデントの設定に関するページです。

ルール違反を修正する

ルールに問題がない場合はソースコードを修正する必要があります。 🔨マークが付いているルールは自動修正に対応しています。

@typescript-eslint/no-inferrable-typesも対応していますので試してみましょう。
--fixオプションをつけて実行します。

npx eslint . --ext .ts --fix

index.tsのコードが以下のように変更されました。

- const hello: string = "ハロー";
+ const hello = "ハロー";

ルールを無効化する

理由があって、特定箇所だけルールを無効化したい場合があると思います。
そのときはコメントで対応します。

ルール名は特定のルール名で置き換えて下さい。
先ほどの例だと@typescript-eslint/no-inferrable-typesです。

  • ルール名を省略すると全てのルールが対象になります
  • ルール名を複数指定する場合はカンマで列挙します

次の行だけ無視したい

// eslint-disable-next-line @typescript-eslint/no-inferrable-types
const hello: string = "ハロー"; // この行だけ無視される

現在行だけ無視したい

const hello: string = "ハロー"; // eslint-disable-line @typescript-eslint/no-inferrable-types

ファイル内の特定行以降をすべて無効化したい

const goodMorning: string = "グッドモーニング"; // エラー
// これより上は無効化されない

/* eslint-disable ルール名 */

// これより下は無効化される
const hello: string = "ハロー"; // この行は無視される

IntelliJ IDEAとの連携

Lintエラーを表示する

IntelliJ IDEAで連携するための設定をしましょう。
ESLintの設定から、Automatic ESLint configurationを選んで下さい。

こんな風にInspectionが表示されればOKです。

Lintエラーを自動修正する

--fixで修正できるルール違反はIntelliJ IDEAのShow Context Actionsから修正できます。

Fix ESLint Problemsを実行すると、ファイルやディレクトリ単位でまとめて修正できます。

IntelliJのInspectionと競合を防ぐ

TypeScriptJavaScriptのInspectionをすべてオフにすると競合しません。
ただし、Code quality tools > ESLintだけはオンのままにしておく必要があります。

足りないInspectionがある場合は、Lintルールを変更するかIntelliJのInspectionを部分的にオンにすれば対処できます。

トラブルシューティング

Prettierと設定が競合する

ESLintにはフォーマットに関するルールがいくつか存在します。
それはPrettierの設定と競合することがあります。

たとえばPrettierのクォーテーションはダブルがデフォルトです。
もしESLintのルールをquotes: ["error", "single"]のようにした場合、以下のような無限ループが発生します。

  1. ダブルクォーテーションの箇所がESLintの怒られる
  2. 1を修正したあと保存すると、Prettierによってダブルクォーテーションへ戻される(1へ)

スタイルトはPrettierに任せるため、ESLintの関連設定を無効にしましょう。
そのためにprettier/eslint-config-prettierを使います。

例に書かれている通り、様々なeslint-plugin設定に対応するラインナップがあります。
使ったことあるのはeslint-plugin-vueのスタイル設定を無効化するprettier/vueですね😄

記事内でprettier/eslint-config-prettierを紹介しないのはなぜ..?

紹介した以下3つの設定にPrettierと競合するようなスタイル設定が含まれていないからです。

  • eslint:recommended
  • plugin:@typescript-eslint/eslint-recommended
  • plugin:@typescript-eslint/recommended

eslint:recommendedではno-mixed-spaces-and-tabs以外のStylistic Issuesはオフになっています。

https://eslint.org/docs/rules/#stylistic-issues

prettier/eslint-config-prettierを使ったらスタイルエラーが拾えなくなった..

prettier/eslint-plugin-prettierを使うと、PrettierのエラーをESLintで拾うことができます。

Webを検索すると、prettier/eslint-config-prettierと併用を勧める情報が多く見つかります。
しかし、私は以下の理由で導入していません。

  • 保存時にPrettierで自動修正させれば開発に一切支障がない
    • ESLintで表示すると、スタイル以外のエラーか目立たなくなってしまう
  • 依存が増え、設定も複雑になり敷居が上がる

本当に導入するメリットがあるか..は一度考えてみる価値があると思います。

namespaceやstatic、import周辺でエラーになる

  1 | import axios from '~/plugins/axios'
  2 |
> 3 | export namespace DiceCompany {
    |                  ^
  19:11  error  Parsing error: Unexpected token

  17 |
  18 | export class Status {
> 19 |   private static readonly _values: Status[] = []
     |           ^
  2:3  error  Parsing error: Imports within a `declare module` body must always be `import type` or `import typeof`

  1 | declare module '*.vue' {
> 2 |   import Vue from 'vue'
    |   ^
  3 |   export default Vue
  4 | }

parserOptionsbabel-eslintがある場合は削除すると解決することがあります。

    parserOptions: {
-     parser: 'babel-eslint'
    },

scriptタグで読み込んだglobal変数がエラーになる

global変数の存在を知らせるため、.eslintrc.jsglobalに追加しましょう。
以下はjQueryとaxiosの例です。

module.exports = {
  // ...中略
  globals: {
    $: 'readonly',
    axios: 'readonly',
  },
}

総括

ESLintをTypeScriptで使う方法、それをIntelliJ IDEAと連携させる方法を紹介しました。

ESLintは設定周りのオプションも多いため、はじめて学ぶにはハードルが高いと思っています。
TypeScriptやPrettier、ReactやVueなどの設定が入ってくると余計そうでしょう。
インストールpackageやプラグイン名、extendsする設定名もすべて同じ名前に見えます..😭

一方、ESLintは使いこなせば非常に強力な武器になります。
特にJavaScriptプロダクトをTypeScriptに移行する際は大変お世話になりました。

1人でも多くの方がESLintを使いこなし、TypeScriptで楽しい開発されることを願っております😊