[React] ESLint

2021-06-12 hit count image

Reactでソースコードを分析してバグやエラーを探すため、ESLintを使う方法について説明します。

react

ブログシリーズ

このブログはシリーズで作成されております。次はブログシリーズのリストです。

概要

ESLintとはES(EcmaScript) + Lint(エラーコード表示)の合成語でJavascriptのコードを分析して、潜在的なエラーやバグを見つけるに役に立つツールです。

このブログポストではcreate-react-appで生成したReactプロジェクトでESLintを適用する方法について説明します。

プロジェクトの準備

ReactでESLintを使うため、create-react-appでプロジェクトを生成してみます。create-react-appに詳しくない方は、下記のブログポストを確認してみてください。

そしたら、次のコマンドを実行してESLintを実行するReactプロジェクトを生成します。

npx create-react-app eslint_example --template=typescript

私は主にTypeScriptを使ってReactを開発してるので--template=typescriptオプションを使ってReactプロジェクトを生成しました。

ESLintのインストール

ReactでESLintを使うためにはESLintのライブラリをインストールする必要があります。次のコマンドを使ってESLintのライブラリをインストールします。

# cd eslint_example
npm install eslint --save-dev

ESLintの設定

ReactでESLintを使うためにはESLintを設定する必要があります。次のコマンドを実行してESLintを設定します。

npx eslint --init

上のコマンドを実行すると、次のような質問が表示されます。

? How would you like to use ESLint?
  To check syntax only
 To check syntax and find problems
  To check syntax, find problems, and enforce code style

自分が使いたいオプションを選択します。私はTo check syntax and find problemsを選択しました。そしたら、下記のような質問が表示されます。

? What type of modules does your project use?
 JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

Reactは基本的import/exportの方法を使ってるので、JavaScript modules (import/export)を選択します。そしたら、下記のように質問が表示されます。

? Which framework does your project use?
 React
  Vue.js
  None of these

私たちはESLintをReactプロジェクトで使う予定なので、Reactを選択して進めます。そしたら、下記のような質問が表示されます。

? Does your project use TypeScript? › No / Yes

私はReactを開発する時、主にTypeScriptを使ってるのでYesを選択して進めました。TypeScriptを使ってない方はNoを選択して進めてください。そしたら、下記のような質問が表示されます。

? Where does your code run? …  (Press <space> to select, <a> to toggle all, <i> to invert selection)
 Browser
 Node

ReactはBrowserでコードが実行されるので、Browserを選択して進めます。そしたら、下記のような質問が表示されます。

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

今まで返信したESLintの設定の内容を保存するファイルのフォーマットを選択するオプションです。私はJavaScriptフォーマットを好むので、JavaScriptを選択しました。

eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
? Would you like to install them now with npm? › No / Yes

最後に、このように設定した内容に必要なライブラリをインストールするかどうか決めるオプションが表示されます。Yesを選択して必要なライブラリをインストールします。

ESLintのルール

ESLintの公式サイトとTypeScript ESLintの公式ページで設定可能なルール(Rule)を確認することができます。

  • ESLintの公式サイト: Rules
  • ESLint Plugin TypeScript: Rules

当該ルールなどを確認して、自分のプロジェクトに合わせてルールを設定することができます。下記のルールは私が使ってるルールの内容です。

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:storybook/recommended',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
    project: './tsconfig.json',
  },
  plugins: ['react', '@typescript-eslint', 'functional', 'import'],
  settings: {
    react: {
      version: 'detect',
    },
  },
  rules: {
    // General
    'no-console': ['error', { allow: ['debug', 'warn', 'error'] }],
    // TypeScript
    '@typescript-eslint/consistent-type-imports': 'error',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/explicit-member-accessibility': 'off',
    '@typescript-eslint/indent': 'off',
    '@typescript-eslint/member-delimiter-style': 'off',
    '@typescript-eslint/no-confusing-void-expression': [
      'error',
      {
        ignoreArrowShorthand: true,
        ignoreVoidOperator: true,
      },
    ],
    'no-duplicate-imports': 'off',
    '@typescript-eslint/no-duplicate-imports': 'error',
    '@typescript-eslint/no-implicit-any-catch': 'error',
    'no-invalid-this': 'off',
    '@typescript-eslint/no-invalid-this': 'error',
    '@typescript-eslint/no-invalid-void-type': 'error',
    'no-loop-func': 'off',
    '@typescript-eslint/no-loop-func': 'error',
    'no-loss-of-precision': 'off',
    '@typescript-eslint/no-loss-of-precision': 'error',
    '@typescript-eslint/no-parameter-properties': 'off',
    'no-redeclare': 'off',
    '@typescript-eslint/no-redeclare': 'error',
    'no-shadow': 'off',
    '@typescript-eslint/no-shadow': 'error',
    'no-throw-literal': 'off',
    '@typescript-eslint/no-throw-literal': 'error',
    '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
    '@typescript-eslint/no-unnecessary-condition': 'error',
    '@typescript-eslint/no-unnecessary-type-arguments': 'error',
    'no-unused-expressions': 'off',
    '@typescript-eslint/no-unused-expressions': 'error',
    '@typescript-eslint/no-unused-vars': 'error',
    '@typescript-eslint/no-use-before-define': [
      'error',
      {
        variables: false,
      },
    ],
    '@typescript-eslint/prefer-enum-initializers': 'error',
    '@typescript-eslint/prefer-for-of': 'error',
    '@typescript-eslint/prefer-includes': 'error',
    '@typescript-eslint/prefer-nullish-coalescing': 'error',
    '@typescript-eslint/prefer-optional-chain': 'error',
    '@typescript-eslint/prefer-reduce-type-parameter': 'error',
    '@typescript-eslint/prefer-string-starts-ends-with': 'error',
    '@typescript-eslint/prefer-ts-expect-error': 'error',
    '@typescript-eslint/promise-function-async': 'error',
    'no-return-await': 'off',
    '@typescript-eslint/return-await': 'error',
    '@typescript-eslint/strict-boolean-expressions': 'error',
    '@typescript-eslint/switch-exhaustiveness-check': 'error',
    // React
    'react/jsx-boolean-value': 'warn',
    'react/jsx-curly-brace-presence': 'warn',
    'react/jsx-fragments': 'warn',
    'react/jsx-no-useless-fragment': 'warn',
    'react/jsx-uses-react': 'off',
    'react/prefer-stateless-function': 'warn',
    'react/prop-types': 'off',
    'react/react-in-jsx-scope': 'off',
    // Functional
    'functional/prefer-readonly-type': [
      'error',
      {
        allowLocalMutation: true,
        allowMutableReturnType: true,
        ignoreClass: true,
      },
    ],
    'import/order': [
      'error',
      {
        groups: ['builtin', 'external', 'internal'],
        pathGroups: [
          {
            pattern: '{react,react-dom/**}',
            group: 'external',
            position: 'before',
          },
        ],
        pathGroupsExcludedImportTypes: ['react'],
        'newlines-between': 'always',
        alphabetize: {
          order: 'asc',
          caseInsensitive: true,
        },
      },
    ],
    'react/react-in-jsx-scope': 'off',
    'linebreak-style': ['error', 'unix'],
    eqeqeq: ['error', 'always', { null: 'ignore' }],
    camelcase: ['error', { properties: 'never' }],
    quotes: ['error', 'single', { avoidEscape: true }],
  },
};

上のルールを使うためには下記のコマンドを実行してeslint-plugin-functionalをインストールする必要があります。

npm install --save-dev eslint-plugin-functional

ESLintのチェック

下記のコマンドを使って私たちが定義したESLintのルールを守ってないファイルと内容を確認することができます。

npx eslint ./src

コマンドを実行すると次のように定義したルールを守ってないファイルと内容が確認できます。

/eslint_test/src/App.tsx
  5:1  warning  Missing return type on function  @typescript-eslint/explicit-module-boundary-types

/eslint_test/src/reportWebVitals.ts
  1:1   error    All imports in the declaration are only used as types. Use `import type`  @typescript-eslint/consistent-type-imports
  3:25  warning  Missing return type on function                                           @typescript-eslint/explicit-module-boundary-types

 3 problems (1 error, 2 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

ESLintでコードを修正

次のコマンドを使うと私たちが定義したESLintのルールを使ってコードを修正することができます。

npx eslint --fix ./src

コマンドを実行するとESLintが修正できるファイルは修正して、修正できないファイルを次のように表示されます。

/eslint_test/src/App.tsx
  5:1  warning  Missing return type on function  @typescript-eslint/explicit-module-boundary-types

/eslint_test/src/reportWebVitals.ts
  3:25  warning  Missing return type on function  @typescript-eslint/explicit-module-boundary-types

修正できなかったファイルはファイルを開いて直接修正します。

// code ./src/App.tsx
function App(): JSX.Element {
// code ./src/reportWebVitals.tsx
const reportWebVitals = (onPerfEntry?: ReportHandler): void => {

このようにファイルを修正して、再びコマンドを実行してコードをチェックしてみると、以前とは違ってエラーが表示されないことが確認できます。

npx eslint ./src

これで私たちが事前に定義したESLintのルールをよく守ってることが分かります。

私はESLintがコードを自動で修正してくれる--fixのオプションをあまり使ってないです。直接コードを見て、理由を分かることも大事だっと思うことと、時々ESLintが間違って修正する場合もあるからです。

package.jsonの設定

上で見たcheckコマンドとfixコマンドをもっと簡単に使えるようにするためpackage.jsonファイルを開いて下記のように修正します。

"scripts": {
  ...
  "lint": "eslint ./src",
  "lint:fix": "eslint --fix ./src"
},

このようにpackage.jsonファイルを修正すると、次のコマンドを実行してESLintを使うことができます。

npm run lint
npm run lint:fix

完了

これでReactプロジェクトでESLintを設定する方法について見てみました。今からESLintを使って潜在的なエラーやバグを直してみてください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。



SHARE
Twitter Facebook RSS