久しぶりにやったのでまとめ。

React アプリの準備

こんな環境を想定しています。

$ create-react-app my-greate-project --typescript --use-npm
  • Node.js v10.16
  • react-scripts v3.0
  • TypeScript v3.5
  • ESLint v5.16
  • @typescript-eslint/eslint-plugin v1.13

手順概要

  1. ESLint本体をインストール
  2. .eslintrc.js を生成、プラグイン類をインストール
  3. TypeScript 用プラグインを追加
  4. ESLint の設定を更新
  5. NPM スクリプト準備
  6. 初期状態から recommended な状態へ対応

ESLint 本体をインストール

本体だけ先んじてインストールします。

$ npm install eslint

まあそれだけ。

.eslintrc.js を生成、プラグイン類をインストール

--init で、対話形式で初期設定をします。

$ npx eslint --init
? How would you like to use ESLint?
❯ To check syntax, find problems, and enforce code style

? What type of modules does your project use?
❯ JavaScript modules (import/export)

? Which framework does your project use?
❯ React

? Where does your code run?
❯ Browser

? How would you like to define a style for your project?
❯ Use a popular style guide

? Which style guide do you want to follow?
❯ Airbnb (https://github.com/airbnb/javascript)

? What format do you want your config file to be in?
❯ JavaScript

? The style guide "airbnb" requires eslint@^4.19.1 || ^5.3.0. You are currently using eslint@6.1.0.
  Do you want to downgrade?
❯ Yes

The config that you've selected requires the following dependencies:

eslint-plugin-react@^7.14.2 eslint-config-airbnb@latest
eslint@^4.19.1 || ^5.3.0 eslint-plugin-import@^2.18.0
eslint-plugin-jsx-a11y@^6.2.3

? Would you like to install them now with npm?
❯ Yes
...

これで .eslintrc.js が出てくる。

TypeScript 用プラグインを追加

ESLint が聞いてくれないので、こいつだけ手動で追加。

$ npm install @typescript-eslint/eslint-plugin

このタイミングでいったん git add しちゃうのお勧めします。今後はこの自動生成されたファイルを手動で更新していくので。

ESLint の設定を更新

.eslintrc.js に設定を足す。(途中の @@ -18,8 +22,31 @@ は中略のことと思ってください。)

diff --git a/.eslintrc.js b/.eslintrc.js
@@ -2,14 +2,18 @@
 module.exports = {
   env: {
     browser: true,
     es6: true,
+    jest: true,
   },
   extends: [
     'airbnb',
+    'plugin:@typescript-eslint/recommended',
+    'plugin:react/recommended',
   ],
   globals: {
     Atomics: 'readonly',
     SharedArrayBuffer: 'readonly',
   },
+  parser: '@typescript-eslint/parser',
   parserOptions: {
     ecmaFeatures: {
       jsx: true,
@@ -18,8 +22,31 @@
 module.exports = {
     sourceType: 'module',
   },
   plugins: [
+    '@typescript-eslint',
     'react',
   ],
+  settings: {
+    'import/resolver': {
+      node: {
+        extensions: ['.js', '.jsx', '.ts', '.tsx'],
+      },
+    },
+  },
   rules: {
+    '@typescript-eslint/indent': [
+      'error',
+      2,
+    ],
+    '@typescript-eslint/no-use-before-define': 'off',
+    '@typescript-eslint/prefer-interface': 'off',
+    'react/jsx-filename-extension': [
+      'error',
+      { 'extensions': ['.jsx', '.tsx'] },
+    ],
+    'spaced-comment': [
+      'error',
+      'always',
+      { markers: ['/ <reference'] },
+    ],
   },
 };

あとルールについてちょっと説明します。

@typescript-eslint/indent

文字通りインデントの量。

plugin:@typescript-eslint/recommended の初期値が 4 なので、個人の趣味に合わせて 2 にする。

@typescript-eslint/prefer-interface

TypeScript で type より interface を使おうってやつ。

「別に interface でなくて type でよくね? いやむしろ type の方がよくね?」というのがどうやら最近の流れで、実際 @typescript-eslint/eslint-plugin の次のメジャーバージョン v2 では recommended から外れるようです。

というわけで、先んじて外しておく。

react/jsx-filename-extension

JSX の記法をどのファイル拡張子で許可するか。例えば .jsx は許可して .js の場合は利用禁止、というのができる。

TS 用に .tsx を追加しとく。これ recommended に入らないかな。

spaced-comment

コメント // の直後は空白を配置する。

TS では Triple-Slash Directives というのがあって、/// を使ってコンパイラーへ指示 (directive) を与えることができます。それがこのルールと衝突するので、例外としてこの記法は通すようにすると。

具体的には src/react-app-env.d.ts がそれです。

/// <reference types="react-scripts" />

NPM スクリプト準備

これで準備できたので、まずはそのまま実行してみます。標準だと .ts, .tsx を見てくれないので--ext で指定します。

$ npx eslint src --ext .ts,.tsx

いっぱいエラーが出るはず、特に src/serviceWorker.ts で。

それは次項に回して、毎回コマンド打たなくて良いよう package.json に書いておきます。

   "scripts": {
+    "lint": "eslint src --ext .ts,.tsx",
     "start": "react-scripts start",

そしたら今後はこう。

$ npm run lint

もし自動修正 --fix をやりたい場合はこうです。

$ npm run lint -- --fix

初期状態から recommended な状態へ対応

頑張ってぽちぽち直していきましょう。特に serviceWorker.ts は大量に出てきてビビるんだけど、実はエラーの種類は多くないので、落ち着いてやれば大丈夫です。

src/App.tsx

こいつだけ修正内容を載せておきます。

diff --git a/src/App.tsx b/src/App.tsx
@@ -1,14 +1,19 @@
-import React from 'react';
+import React, { ReactElement } from 'react';
 import logo from './logo.svg';
 import './App.css';
 
-const App: React.FC = () => {
+// eslint-disable-next-line arrow-body-style
+const App: React.FC = (): ReactElement => {
   return (
     <div className="App">
       <header className="App-header">
         <img src={logo} className="App-logo" alt="logo" />
         <p>
-          Edit <code>src/App.tsx</code> and save to reload.
+          Edit
+          {' '}
+          <code>src/App.tsx</code>
+          {' '}
+          and save to reload.
         </p>
         <a
           className="App-link"
@@ -21,6 +26,6 @@
       </header>
     </div>
   );
-}
+};
 
 export default App;

開発を進めたらきっと {} が必要になるので、arrow-body-style を一時的に無効化しています。必要ないならいいです。

No files matching ‘src’ were found.

コンソールの入力 で --ext を忘れてる。

Missing return type on function (@typescript-eslint/explicit-function-return-type)

実際の戻り値を見ながら明示してやる。だいたい () => …(): void => … にすれば解決する。

Unexpected console statement (no-console)

デバッグ用コードである console.log() 等が残っている。

故意に残す場合、その行を無視する。

+// eslint-disable-next-line no-console
 console.log('Here');

serviceWorker.ts の場合は全体的に出していきたい感じ?っぽいので、ファイル全体を無効化することにする。ファイル冒頭にこれ↓を書く。

+/* eslint-disable no-console */

Assignment to property of function parameter ‘xxx’ (no-param-reassign)

受け取った引数(あるいはそのプロパティ)を上書きしている。

serviceWorker.ts の場合は特に問題ないので、その行は無視する。

+      // eslint-disable-next-line no-param-reassign
       registration.onupdatefound = (): void => {

おまけ:VS Code のプラグイン設定

ESLint を CLI から毎回実行するより、エディター上で確認して対応していく方が楽です。

VS Code の場合はプラグイン導入で実現できます。

TypeScript に対応させるには設定が必要です。VS Code の設定 JSON ファイルを開いて(Ctrl + , → 右上 “{}” ボタン)、こんな設定。

{
…
    "eslint.autoFixOnSave": true,
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        {"language": "typescript", "autoFix": true },
        {"language": "typescriptreact", "autoFix": true }
    ],
…

“autoFix” はファイル保存時に自動で修正(できる場合に)してくれる機能です。好みだけども ON にしとくと良いと思います。TS の場合はこう↑書いておかないと利かない。

TypeScript が新しすぎる警告

こんなん言われる。

WARNING: You are currently running a version of TypeScript which is not officially supported by typescript-estree.

You may find that it works just fine, or you may not.

SUPPORTED TYPESCRIPT VERSIONS: >=3.2.1 <3.5.0

YOUR TYPESCRIPT VERSION: 3.5.3

Please only submit bug reports when using the officially supported version.

よくわからない。既に解決済みのようだけど。

The update was merged on 6 Jun as you can see above, and it was released to the latest tag on npm on the 9th of June: https://github.com/typescript-eslint/typescript-eslint/releases/tag/v1.10.1

使ってるのは v1.13 なんだけどなあ。

おわり

linter は早めに入れるのがお得です。

参考