【ESLint】個人テンプレートのESLintを改善するためにeslint-config-airbnbを調査してみる
モチベーション
- 個人テンプレートのESLintをアップデートさせる
- airbnbのルールセットをベースに案件に合わせたルールを設定したい
- airbnbでどのようなルールセットが適応されているのか探すのが面倒なので設定ファイルのリンクを載せて辞書っぽい記事にしたい
改善前のESLint
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"airbnb",
"airbnb-typescript",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module",
"project": "./tsconfig.json"
},
"plugins": ["react", "react-hooks", "@typescript-eslint"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "error",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-throw-literal": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"react/require-default-props": "off",
"spaced-comment": "off",
"no-console": "off",
"no-alert": "off",
"arrow-body-style": "off",
"import/prefer-default-export": "off",
"@typescript-eslint/no-shadow": "off",
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/no-unused-vars": "off",
"react/prop-types": "off",
"react/jsx-props-no-spreading": "off",
"react/react-in-jsx-scope": "off",
"react/function-component-definition": [
2,
{ "namedComponents": "arrow-function" }
]
}
}
※2024年8月3日に更新しました
eslint-config-airbnb
eslint-config-airbnbをちゃんと理解したいので改めてREADMEを読んでみましょう
私たちのデフォルトのエクスポートには、ECMAScript 6+とReactを含む、私たちのESLintルールのほとんどが含まれています。eslint、eslint-plugin-import、eslint-plugin-react、eslint-plugin-react-hooks、eslint-plugin-jsx-a11yを必要とします。
以下のコマンドでeslint-config-airbnb
+ eslint
、eslint-plugin-import
、eslint-plugin-react
、eslint-plugin-react-hooks
、eslint-plugin-jsx-a11y
がdevDependenciesにインストールされます
$ npx install-peerdeps --dev eslint-config-airbnb
使用する際は.eslintrc.json以下のように追加します
"extends": ["airbnb"]
実際にairbnbでexportされているのはairbnb-baseとreactとreact-a11yになります
もしReact周りの設定が不要な場合は.eslintrc.jsonを以下のように指定することでreact周りのルールセットを排除することができます
"extends": ["airbnb-base"]
eslint-plugin-react-hooks
を有効にするにはairbnb/hooksをextendsに追加する必要があります。
このエントリポイントでは、Reactフックのlintingルールを有効にします(v16.8+が必要です)。使用するには、"extends "を追加します:.eslintrc に ["airbnb", "airbnb/hooks"] を追加します。
"extends": ["airbnb", "airbnb/hooks"]
eslint-config-airbnb
がeslint-plugin-react
, eslint-plugin-react-hooks
, eslint-plugin-jsx-a11y
のどのようなルールを設定をしているかは下記から確認することができます
これでairbnbのルールセットの追加は完了です。思ったよりも簡単ですね。
airbnb/hooksとreact-hooks/recommendedの設定を比較してみる
eslint-plugin-react-hooks
のairbnbのルールセット(airbnb/hooks)とrecommendのルールセット(react-hooks/recommended)を比較してどのような違いがあるか見ていきましょう
airbnb/hooksの場合
react-hooks/rules-of-hooks
とreact-hooks/exhaustive-deps
がerrorで設定されています
react-hooks/recommendedの場合
airbnbと違ってreact-hooks/exhaustive-deps
がwarnで設定されています
これらから読み取れるようにairbnb/hooks
の方が厳しめに設定していることがわかります。個人的にはreact-hooks/exhaustive-deps
をerrorにするのは厳しすぎるかなと思うのでwarnにしたいのですが以下の選択をする必要がありそうです。
-
airbnb/hooks
だけを導入し、rulesで'react-hooks/exhaustive-deps': 'warn'
として設定を上書きする - react-hooks/recommendedだけを導入しデフォルト設定を受け入れる
個人的にはベースをairbnbで揃えたい気持ちがあったので前者を選択しました
airbnb-typescript
Reactのプロジェクトを進める上でTypeScriptは必須になると思います。airbnbはTypeScriptのルールセットも提供していてtypescript-airbnb
というものがあります。こちらもみていきましょう。
READMEに記載がある通りにインストールを進めます。
npm install eslint-config-airbnb-typescript \
@typescript-eslint/eslint-plugin@^7.0.0 \
@typescript-eslint/parser@^7.0.0 \
--save-dev
"extends": ["airbnb", "airbnb-typescript"]
これでairbnb-typescriptのルールセットの追加は完了です。こちらも簡単でしたね。
typescript-airbnbと@typescript-eslint/recommendedの設定を比較してみる
具体的には@typescript-eslint/no-shadow
にスポットを当てて設定内容を比較していこうと思います(こだわりはないのでなんとなくでno-shadowをピックアップしました)
@typescript-eslint/recommended
ドキュメントと実際のコードを見てみましたが@typescript-eslint/no-shadow
を@typescript-eslint/recommended
ではデフォルト設定していないようなので特にワーニングやエラーが起きることはありません
もし@typescript-eslint/no-shadow
を有効させるには別途rulesに設定を追加する必要があります
// 以下をrulesに追加
"@typescript-eslint/no-shadow": "error",
typescript-airbnb
一方でtypescript-airbnb
では@typescript-eslint/no-shadow
が有効化されているのでrulesに追記しなくてもリントエラーが出ます。
typescript-airbnb
と@typescript-eslint/recommended
のルールセットを全てを比較したわけではありませんがairbnbの方が厳しめ設定していそうです
個人テンプレートのESLintをアップデートさせる
ようやく個人テンプレートのESLintをアップデートさせるパートです。量も多くなりそうなので@typescript-eslint/〇〇
のルールに焦点を当ててアップデートさせていきたいと思います。
非nullアサーション演算子(Non-Null Assertion Operator)をブロックする
nullチェックすれば良いのを妥協していたので削除
// 以下を削除
"@typescript-eslint/no-non-null-assertion": "off"
Error オブジェクトの代わりに数値や文字列、boolean などのリテラルを投げるのをブロックする
そもそもErrorオブジェクト以外を投げようとしていた背景が不明だったので削除
// 以下を削除
"@typescript-eslint/no-throw-literal": "off"
戻り値に明示的に型をつけない関数をブロックする
業務委託先で導入されているので真似て導入していたが思った以上にvoid祭りになっていて旨味を感じなかったので削除。jsxファイルにも適用するには別途overridesする必要がある。
// 以下を削除
"@typescript-eslint/explicit-module-boundary-types": "error"
外部スコープで宣言された変数と同じ名前の変数を宣言することブロックする
再帰的な処理でもない限りは変数名を被らせない方が良いと思ったので削除
// 以下を削除
"@typescript-eslint/no-shadow": "off",
// エラーが発生する具体例
const {
register,
setValue,
formState: { errors },
watch,
handleSubmit
} = useForm<FormData>({
resolver: yupResolver(getSchema())
})
const onError: SubmitErrorHandler<FormData> = (errors) => {}
// 引数の変数(errors)がreact-hook-formのerrorsと被るのでエラーが発生する
明示的なany型の利用をブロックする
any絶対許さないマン。と言いながら時には必要な場合もあるのでerrorで設定するのではなく、rulesから削除しデフォルトのwarnを適用させる。
// 以下を削除
"@typescript-eslint/no-explicit-any": "off",
最後に
長くなりましたが一旦これでFIXさせようと思います。もし間違い等ありましたらご指摘いただけますと幸いです。最後までご覧いただきありがとうございました。
改善後のESLint
{
"extends": ["airbnb", "airbnb/hooks", "airbnb-typescript", "prettier"],
"parserOptions": {
"project": "./tsconfig.json"
},
"rules": {
// eslint-config-airbnb(eslint)
"spaced-comment": "off",
"no-console": "off",
"no-alert": "off",
"arrow-body-style": "off",
// eslint-config-airbnb(eslint-plugin-import)
"import/prefer-default-export": "off",
// eslint-config-airbnb(eslint-plugin-react)
"react/require-default-props": "off",
"react/prop-types": "off",
"react/jsx-props-no-spreading": "off",
"react/react-in-jsx-scope": "off",
// eslint-config-airbnb(eslint-plugin-react-hook)
"react-hooks/exhaustive-deps": "warn",
// eslint-config-airbnb-typescript(eslint-typescript)
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-unused-vars": "off"
}
}
Next.jsのプロジェクトでもairbnbのルールセットは使えるの?
記事を更新したタイミングで個別の質問があったため補足します。
Q, Next.jsのプロジェクトでもairbnbのルールセットは使えるの?
A, はい、大丈夫です
少しNext.js側で用意しているeslint-config-nextの説明も交えながら解説していきます。
Next.jsは環境構築の段階でESLintを有効にする選択をした場合、自動でeslint-config-next
が.eslintrc.jsonに追加されていると思います。
添付したeslint-config-next
の中身を見ていただけるとわかると思いますが、airbnbでインストールしたものと同じパッケージが利用されています。そのため大枠は同じだと思っていて、airbnbのコンセプトを選択するか、nextのコンセプトを選択するかの差だと考えています。無難にNext.jsのプロジェクトを進めるなら最適化されているであろうnextのルールセットをチョイスするのが良いかなと思いました。
もし両方とも取り入れたい場合は、extendsの順番に注意してください。後出しが優先されるので、例えば改善後のESLint
を以下のように変更した場合、nextのルールが優先される(オーバーライドする)のでairbnbのルールを骨子にメインはnextのルールにすることができます。
全体感を見た時にどっちをオーバーライドさせるかはルールを全て比較していないので保証はできませんが、Next.jsを使っているならnextがメインになるように設定したほうが良いと思いました。
// nextのルールセットが優先される
"extends": ["airbnb", "airbnb/hooks", "airbnb-typescript", "next/core-web-vitals", "prettier"]
eslint-config-next
eslint-config-next/core-web-vitals
厳格にする場合はnext/core-web-vitals
を指定します。
参考記事
Discussion