t28.dev

typescript-eslint v6 で built-in configurations の構造が変わったので、ルールの対応表を作って眺める

2024/1/3
Tech

typescript-eslint v6

QOL を上げる v6

TypeScript に対して ESLint を実行出来るようにする typescript-eslint の v6 がリリースされました 1。 v6 には生活の質を上げる機能が備わっている(本当に書いてある)ようなので、 私の QOL も爆上げしようと思います。

Major update ということで Breaking change があるのですが、注目ポイントは @typescript-eslint/eslint-plugin の built-in configurations 2 の構造が変わった点です。 built-in configurations とは typescript-eslint がおすすめするルール(やパーサーの設定)を持った ESLint shareable configurations のことです。

v5 の built-in configurations の構造と課題

v5 では recommended (おすすめルール) をベースに、recommended-requiring-type-checking (型情報が必要なルール) 、strict (もっと厳しいルール)を必要に応じて追加で extends することで、ESLint の設定がいい感じに出来るというものでした。

module.exports = {
  extends: [
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "plugin:@typescript-eslint/strict",
  ],
};

v5 の構造に対して、typescript-eslint は以下のような課題を認識しています。

  1. strict 内に 型チェックが必要/不要なルールが混在している
  2. 文体のベストプラクティスのルールとバグを見つけるルールが混在している

v6 の built-in configurations の構造

そのため、v6 では 1. を解決するために以下のような built-in configurations を提供するようになりました。

  • recommended: バッドプラクティスやバグの可能性を報告するための、おすすめルールを含む設定
  • strict: recommended に加えて、さらに厳しいルールを含む設定
  • stylistic: ロジックに影響を与えない (つまり文体の指摘のみ) 、モダンな TypeScript のコードにするルールを含む設定

さらに、2. を解決するために型情報が必要なルールを含む設定は *-type-checked という suffix の built-in configurations で提供するようになりました。

この新しい built-in configurations の構造によって、typescript-eslint ユーザーは以下のような設定を行うことになります。

// 🥰型安全なルールをコミュニティのおすすめで設定したいな〜
module.exports = {
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended-type-checked",
    "plugin:@typescript-eslint/stylistic-type-checked",
  ],
  parserOptions: {
    project: true,
    tsconfigRootDir: __dirname,
  },
};
// 🥳型情報を使わない範囲で、厳しくリントする!
module.exports = {
  extends: ["eslint:recommended", "plugin:@typescript-eslint/strict"],
};

[本題] v5-v6 の built-in configurations のルールの差分が知りたい

「コミュニティのおすすめに乗っかるぜ!」勢としては、v5-v6 間で built-in configurations が設定するルールに変更があったということで、

具体的にどのルールがどの built-in configurations で定義されるようになったの?

という気持ちになります3 。例えば、以下の 2 つは同等の設定なの?多分違うよね?…って感じの探究心。

// v5
module.exports = {
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
  ],
  // 略
};
// v6
module.exports = {
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended-type-checked",
    "plugin:@typescript-eslint/stylistic-type-checked",
  ],
  // 略
};

v5 基準で比較する

v5 の built-in configurations 内のルールが、v6 の built-in configurations のどこで定義されているかを調べてみる。

表の見方
  • ✅:◯ のとき、ルールは v6 の recommended に含まれている
  • ✅💭:◯ のとき、ルールは v6 の recommended-type-checked に含まれている
  • 🔒:◯ のとき、ルールは v6 の strict に含まれている
  • 🔒💭:◯ のとき、ルールは v6 の strict-type-checked に含まれている
  • 🎨:◯ のとき、ルールは v6 の stylistic に含まれている
  • 🎨💭:◯ のとき、ルールは v6 の stylistic-type-checked に含まれている

v5 の recommended のルールを持つ “v6 の built-in configurations” を確認する表

v5 rule✅💭🔒🔒💭🎨🎨💭
@typescript-eslint/adjacent-overload-signatures----
@typescript-eslint/ban-ts-comment--
@typescript-eslint/ban-types--
no-array-constructor--
@typescript-eslint/no-array-constructor--
no-empty-function----
@typescript-eslint/no-empty-function----
@typescript-eslint/no-empty-interface----
@typescript-eslint/no-explicit-any--
@typescript-eslint/no-extra-non-null-assertion--
no-extra-semi------
@typescript-eslint/no-extra-semi------
@typescript-eslint/no-inferrable-types----
no-loss-of-precision--
@typescript-eslint/no-loss-of-precision--
@typescript-eslint/no-misused-new--
@typescript-eslint/no-namespace--
@typescript-eslint/no-non-null-asserted-optional-chain--
@typescript-eslint/no-non-null-assertion----
@typescript-eslint/no-this-alias--
@typescript-eslint/no-unnecessary-type-constraint--
no-unused-vars--
@typescript-eslint/no-unused-vars--
@typescript-eslint/no-var-requires--
@typescript-eslint/prefer-as-const--
@typescript-eslint/prefer-namespace-keyword----
@typescript-eslint/triple-slash-reference--

v5 の recommended-requiring-type-checking のルールを持つ “v6 の built-in configurations” を確認する表

v5 rule✅💭🔒🔒💭🎨🎨💭
@typescript-eslint/await-thenable----
@typescript-eslint/no-floating-promises----
@typescript-eslint/no-for-in-array----
no-implied-eval----
@typescript-eslint/no-implied-eval----
@typescript-eslint/no-misused-promises----
@typescript-eslint/no-unnecessary-type-assertion----
@typescript-eslint/no-unsafe-argument----
@typescript-eslint/no-unsafe-assignment----
@typescript-eslint/no-unsafe-call----
@typescript-eslint/no-unsafe-member-access----
@typescript-eslint/no-unsafe-return----
require-await----
@typescript-eslint/require-await----
@typescript-eslint/restrict-plus-operands----
@typescript-eslint/restrict-template-expressions----
@typescript-eslint/unbound-method----
  • 全てのルールが v6 のrecommended-type-checkedstrict-type-checked で扱われている

strict

v5 の strict のルールを持つ “v6 の built-in configurations” を確認する表

v5 rule✅💭🔒🔒💭🎨🎨💭
@typescript-eslint/array-type----
@typescript-eslint/ban-tslint-comment----
@typescript-eslint/class-literal-property-style----
@typescript-eslint/consistent-generic-constructors----
@typescript-eslint/consistent-indexed-object-style----
@typescript-eslint/consistent-type-assertions----
@typescript-eslint/consistent-type-definitions----
dot-notation-----
@typescript-eslint/dot-notation-----
@typescript-eslint/no-base-to-string----
@typescript-eslint/no-confusing-non-null-assertion----
@typescript-eslint/no-duplicate-enum-values--
@typescript-eslint/no-dynamic-delete----
@typescript-eslint/no-extraneous-class----
@typescript-eslint/no-invalid-void-type----
@typescript-eslint/no-meaningless-void-operator-----
@typescript-eslint/no-mixed-enums-----
@typescript-eslint/no-non-null-asserted-nullish-coalescing----
no-throw-literal-----
@typescript-eslint/no-throw-literal-----
@typescript-eslint/no-unnecessary-boolean-literal-compare-----
@typescript-eslint/no-unnecessary-condition-----
@typescript-eslint/no-unnecessary-type-arguments-----
@typescript-eslint/no-unsafe-declaration-merging--
@typescript-eslint/no-unsafe-enum-comparison----
no-useless-constructor----
@typescript-eslint/no-useless-constructor----
@typescript-eslint/non-nullable-type-assertion-style-----
@typescript-eslint/prefer-for-of----
@typescript-eslint/prefer-function-type----
@typescript-eslint/prefer-includes-----
@typescript-eslint/prefer-literal-enum-member----
@typescript-eslint/prefer-nullish-coalescing-----
@typescript-eslint/prefer-optional-chain-----
@typescript-eslint/prefer-reduce-type-parameter-----
@typescript-eslint/prefer-return-this-type-----
@typescript-eslint/prefer-string-starts-ends-with-----
@typescript-eslint/prefer-ts-expect-error----
@typescript-eslint/unified-signatures----

v6 基準で比較する

表の見方
  • in type-checked: 💭 のとき、ルールは *-type-checked にも含まれている
  • ✅  : ◯ のとき、ルールは v5 の recommended に含まれている
  • ✅💭: ◯ のとき、ルールは v5 の recommended-requiring-type-checking に含まれている
  • 🔒  : ◯ のとき、ルールは v5 の strict に含まれている

v6 の recommended のルールを持つ “v5 の built-in configurations” を確認する表

v6 rulein type-checked✅💭🔒
@typescript-eslint/await-thenable💭--
@typescript-eslint/ban-ts-comment--
@typescript-eslint/ban-types--
no-array-constructor--
@typescript-eslint/no-array-constructor--
@typescript-eslint/no-base-to-string💭--
@typescript-eslint/no-duplicate-enum-values--
@typescript-eslint/no-duplicate-type-constituents💭---
@typescript-eslint/no-explicit-any--
@typescript-eslint/no-extra-non-null-assertion--
@typescript-eslint/no-floating-promises💭--
@typescript-eslint/no-for-in-array💭--
no-implied-eval💭--
@typescript-eslint/no-implied-eval💭--
no-loss-of-precision--
@typescript-eslint/no-loss-of-precision--
@typescript-eslint/no-misused-new--
@typescript-eslint/no-misused-promises💭--
@typescript-eslint/no-namespace--
@typescript-eslint/no-non-null-asserted-optional-chain--
@typescript-eslint/no-redundant-type-constituents💭---
@typescript-eslint/no-this-alias--
@typescript-eslint/no-unnecessary-type-assertion💭--
@typescript-eslint/no-unnecessary-type-constraint--
@typescript-eslint/no-unsafe-argument💭--
@typescript-eslint/no-unsafe-assignment💭--
@typescript-eslint/no-unsafe-call💭--
@typescript-eslint/no-unsafe-declaration-merging--
@typescript-eslint/no-unsafe-enum-comparison💭--
@typescript-eslint/no-unsafe-member-access💭--
@typescript-eslint/no-unsafe-return💭--
no-unused-vars--
@typescript-eslint/no-unused-vars--
@typescript-eslint/no-var-requires--
@typescript-eslint/prefer-as-const--
require-await💭--
@typescript-eslint/require-await💭--
@typescript-eslint/restrict-plus-operands💭--
@typescript-eslint/restrict-template-expressions💭--
@typescript-eslint/triple-slash-reference--
@typescript-eslint/unbound-method💭--

strict / strict-type-ckecked

v6 の strict または strict-type-ckecked のルールを持つ “v5 の built-in configurations” を確認する表

v6 ruletype-checked only✅💭🔒
@typescript-eslint/no-confusing-void-expression💭---
@typescript-eslint/no-dynamic-delete--
@typescript-eslint/no-extraneous-class--
@typescript-eslint/no-invalid-void-type--
@typescript-eslint/no-meaningless-void-operator💭--
@typescript-eslint/no-mixed-enums💭--
@typescript-eslint/no-non-null-asserted-nullish-coalescing--
@typescript-eslint/no-non-null-assertion--
no-throw-literal💭--
@typescript-eslint/no-throw-literal💭--
@typescript-eslint/no-unnecessary-boolean-literal-compare💭--
@typescript-eslint/no-unnecessary-condition💭--
@typescript-eslint/no-unnecessary-type-arguments💭--
no-useless-constructor--
@typescript-eslint/no-useless-constructor--
@typescript-eslint/prefer-includes💭--
@typescript-eslint/prefer-literal-enum-member--
@typescript-eslint/prefer-reduce-type-parameter💭--
@typescript-eslint/prefer-return-this-type💭--
@typescript-eslint/prefer-ts-expect-error--
@typescript-eslint/unified-signatures--

NOTE: strict(-type-checked) は recommended(-type-checked) が扱うルールも含む ので、重複するルールは省略している

stylistic/stylistic-type-checked

v6 の stylistic または stylistic-type-checked のルールを持つ “v5 の built-in configurations” を確認する表

v6 rulein type-checked✅💭🔒
@typescript-eslint/adjacent-overload-signatures--
@typescript-eslint/array-type--
@typescript-eslint/ban-tslint-comment--
@typescript-eslint/class-literal-property-style--
@typescript-eslint/consistent-generic-constructors--
@typescript-eslint/consistent-indexed-object-style--
@typescript-eslint/consistent-type-assertions--
@typescript-eslint/consistent-type-definitions--
dot-notation💭--
@typescript-eslint/dot-notation💭--
@typescript-eslint/no-confusing-non-null-assertion--
no-empty-function--
@typescript-eslint/no-empty-function--
@typescript-eslint/no-empty-interface--
@typescript-eslint/no-inferrable-types--
@typescript-eslint/non-nullable-type-assertion-style💭--
@typescript-eslint/prefer-for-of--
@typescript-eslint/prefer-function-type--
@typescript-eslint/prefer-namespace-keyword--
@typescript-eslint/prefer-nullish-coalescing💭--
@typescript-eslint/prefer-optional-chain💭--
@typescript-eslint/prefer-string-starts-ends-with💭--
  • v5 では strict 扱いだったルールが v6 では stylistic になっているものがある

typescript-eslint の recommended な設定を以下と勝手に決めた上で、どんな違いがあるか見てみる。

  • v5
    • plugin:@typescript-eslint/recommended
    • plugin:@typescript-eslint/recommended-requiring-type-checking
  • v6
    • plugin:@typescript-eslint/recommended-type-checked
    • plugin:@typescript-eslint/stylistic-type-checked
表の見方
  • v5: ◯ のとき、ルールは v5 の recommended または recommended-requiring-type-checking に含まれている
  • v6: ◯ のとき、ルールは v6 の recommended-type-checked または stylistic-type-checked に含まれている
rulev5v6
no-extra-semi-
@typescript-eslint/no-extra-semi-
@typescript-eslint/no-non-null-assertion-
@typescript-eslint/no-base-to-string-
@typescript-eslint/no-duplicate-enum-values-
@typescript-eslint/no-duplicate-type-constituents-
@typescript-eslint/no-redundant-type-constituents-
@typescript-eslint/no-unsafe-declaration-merging-
@typescript-eslint/no-unsafe-enum-comparison-
@typescript-eslint/array-type-
@typescript-eslint/ban-tslint-comment-
@typescript-eslint/class-literal-property-style-
@typescript-eslint/consistent-generic-constructors-
@typescript-eslint/consistent-indexed-object-style-
@typescript-eslint/consistent-type-assertions-
@typescript-eslint/consistent-type-definitions-
dot-notation-
@typescript-eslint/dot-notation-
@typescript-eslint/no-confusing-non-null-assertion-
@typescript-eslint/non-nullable-type-assertion-style-
@typescript-eslint/prefer-for-of-
@typescript-eslint/prefer-function-type-
@typescript-eslint/prefer-nullish-coalescing-
@typescript-eslint/prefer-optional-chain-
@typescript-eslint/prefer-string-starts-ends-with-

NOTE: v5, v6 両方に含まれているルールは除外している

  • v5 で strict だったルールが stylistic に移っている分、v6 の方がルールが多くなっている

まとめ・所感

  • typed linting の観点では、-type-checked suffix の有無で整理されただけなので、v5-v6 間で気にすることはあまりなさそう
  • ルールのジャンル分け (recommneded/strict/stylistic) の観点では、v5 のstrictstylistic に移行されている分、stylisticrecommended のノリで設定すると厳しすぎ…ってなりそう (がんばろう)

表を作るためのスクリプト

https://gist.github.com/TatsuyaYamamoto/ff128ca667348ead4295e548ffe586cb

Footnotes

  1. さも最近出た感じの文体だけれど、Announcing typescript-eslint v6 は 2023/07/09 (半年くらい前) のポスト…。

  2. “typescript-eslint が提供している設定ファイル” の表記ゆれが激しい…。configurations, built-in configurations, provided user configuration files…。 個人的には configurations だと意味が広すぎる気がする。

  3. 本当の意味で「コミュニティのおすすめに乗っかるぜ!」勢は、四の五の言わずにアップデートして新しいリントエラーを直すのだろうけれど…。