⌨️

コード品質を保つ ESLint のルール設定

に公開

はじめに

ESLint は JavaScript/TypeScript プロジェクトにおいて、コードの品質を保つために欠かせないツールです。適切な設定により、チーム全体でコードの一貫性を保ち、バグの早期発見やメンテナンス性の向上を実現できます。

本記事では、当プロジェクトで採用している ESLint 設定を、その目的や効果に応じて以下のカテゴリーに分類して解説します:

  • 可読性(Readability): コードの読みやすさを向上させるルール
  • メンテナンス性(Maintainability): 長期的な保守性を高めるルール
  • 品質・複雑性管理(Quality & Complexity): コードの品質と複雑性を制御するルール
  • 型安全性(Type Safety): TypeScript による型安全性を強化するルール
  • テスト(Testing): テストコードの品質を保つルール

可読性(Readability)

コードフォーマット統一

{
  "plugins": ["@stylistic"],
  "rules": {
    "@stylistic/linebreak-style": ["error", "unix"],
    "@stylistic/no-multi-spaces": "error",
    "object-shorthand": "error"
  }
}

@stylistic/linebreak-style: Unix形式(LF)の改行コードを強制することで、異なるOS間でのファイル差分を防ぎます。

@stylistic/no-multi-spaces: 不要な複数スペースを禁止し、コードの見た目を統一します。

object-shorthand: ES6のオブジェクトショートハンド記法を強制し、冗長な記述を避けます。

注意:ESLint v8.53.0以降、linebreak-styleno-multi-spacesなどのフォーマット系ルールが非推奨となりました。これらのルールを継続して使用するには、上記のように@stylistic/eslint-pluginを使用することを推奨します。

React/JSX フォーマット統一

{
  "react/jsx-boolean-value": "error",
  "react/jsx-closing-bracket-location": "error", 
  "react/jsx-closing-tag-location": "error",
  "react/jsx-curly-spacing": "error",
  "react/jsx-pascal-case": "error",
  "react/jsx-tag-spacing": "error",
  "react/jsx-wrap-multilines": "error",
  "react/self-closing-comp": "error"
}

これらのルールにより、JSXの書式が統一され、チーム全体で一貫したReactコードを書くことができます:

Import文の整理

{
  "import/order": [
    "error",
    {
      "alphabetize": { "order": "asc" },
      "groups": ["builtin", "external", "parent", "sibling", "index", "object", "type"],
      "newlines-between": "always",
      "pathGroups": [
        {
          "group": "builtin",
          "pattern": "{react,react-dom/**,react-router-dom}",
          "position": "before"
        }
        // ... 他のパスグループ設定
      ]
    }
  ]
}

import/order: import文をアルファベット順で整理し、グループ間に改行を入れることで、依存関係が一目で分かる構造にしています。

命名規則の統一

{
  "@typescript-eslint/naming-convention": [
    "error",
    {
      "format": ["PascalCase", "camelCase", "UPPER_CASE"],
      "selector": "variable"
    },
    {
      "format": ["PascalCase"], 
      "selector": "typeLike"
    },
    {
      "format": ["PascalCase", "camelCase"],
      "selector": "function"
    }
  ]
}

@typescript-eslint/naming-convention: 変数、型、関数の命名規則を統一することで、コードの可読性を大幅に向上させています。

コードの明示性

{
  "curly": "error",
  "no-implicit-coercion": [
    "error",
    { "allow": ["!!"] }
  ]
}

curly: if文で必ずブレースを使用し、意図しない動作を防ぎます。

no-implicit-coercion: 意図しない型変換を防ぎ、明示的な変換を促します(!!による真偽値変換は例外として許可)。

メンテナンス性(Maintainability)

未使用コードの検出

{
  "@typescript-eslint/no-unused-vars": [
    "error",
    {
      "argsIgnorePattern": "^_",
      "varsIgnorePattern": "^_"
    }
  ],
  "unused-imports/no-unused-imports": "error",
  "import/no-duplicates": "error"
}

@typescript-eslint/no-unused-vars: デッドコードを検出し、コードベースをクリーンに保ちます。_で始まる変数は意図的な未使用として扱います。

unused-imports/no-unused-imports: 未使用のimport文を検出し、自動削除を促します。

import/no-duplicates: 同じモジュールの重複importを防ぎ、バンドルサイズの最適化にも貢献します。

ファイル・関数サイズ制限

{
  "max-lines": [
    "error",
    {
      "max": 300,
      "skipBlankLines": true,
      "skipComments": true
    }
  ],
  "max-lines-per-function": [
    "error", 
    {
      "max": 30,
      "skipBlankLines": true,
      "skipComments": true
    }
  ]
}

max-lines: 300行を超えるファイルは分割を促し、単一責任の原則を守りやすくします。

max-lines-per-function: 30行を超える関数は分割を促し、テストしやすく理解しやすいコードを促進します。

コード構成とインポート管理

{
  "no-restricted-imports": [
    "error",
    {
      "patterns": ["../*"]
    }
  ],
  "react/no-multi-comp": "error"
}

no-restricted-imports: ../を含む相対パスを禁止し、絶対パスでのimportを強制することで、ファイル移動時の影響を最小限に抑えます。

react/no-multi-comp: 1つのファイルに複数のReactコンポーネントを定義することを禁止し、コンポーネントの責任を明確にします。

品質・複雑性管理(Quality & Complexity)

複雑性の制御

{
  "complexity": [
    "error",
    { "max": 10 }
  ],
  "max-depth": [
    "error", 
    { "max": 3 }
  ],
  "max-params": "error",
  "no-nested-ternary": "error"
}

complexity: 関数の複雑度を10以下に制限し、理解しやすい関数を促進します。

循環複雑度(Cyclomatic Complexity)は、関数内の分岐(if文、switch文、ループ等)の数によって決まる複雑さの指標です。値が高いほどバグが混入しやすく、テストが困難になります。

max-depth: 3レベルを超えるネストを警告し、早期return等のパターンを促します。

max-params: 多すぎるパラメータを警告し、オブジェクト化やBuilder パターンの検討を促します。

no-nested-ternary: 可読性を著しく損なうネストした三項演算子を警告します。

型安全性(Type Safety)

{
  "extends": ["plugin:@typescript-eslint/recommended"],
  "parser": "@typescript-eslint/parser"
}

TypeScript ESLint推奨ルールを適用し、型安全性を最大限に活用します。これにより:

  • 型の不整合を早期に検出
  • null/undefined エラーの防止
  • 未定義プロパティアクセスの防止

テスト(Testing)

{
  "files": ["*.test.ts", "*.test.tsx"],
  "plugins": ["jest"],
  "extends": ["plugin:jest/recommended"],
  "rules": {
    "jest/consistent-test-it": [
      "error",
      {
        "fn": "test",
        "withinDescribe": "test"
      }
    ]
  }
}

テストファイルでは一部のルールを緩和し、テストの可読性を優先します:

まとめ

適切に設定されたESLintは、以下の価値を提供します:

  1. 一貫性:チーム全体でコードスタイルが統一される
  2. 品質:バグの早期発見と予防
  3. メンテナンス性:長期的な保守が容易になる
  4. 学習効果:良いプラクティスが自然と身につく
  5. 効率性:コードレビューで形式的な指摘が減り、本質的な議論に集中できる

ESLintの設定は「制約」ではなく、チーム全体の開発効率を向上させる「ガードレール」として機能します。適切な設定により、開発者はより創造的で価値の高い作業に集中できるようになります。

参考資料

SUPER STUDIOテックブログ

Discussion