見出し画像

typescript-eslint/naming-conventionを導入してみた

はじめまして

おはこんばんちは。ラクス フロントエンドチームのさねです。
2022年8月時点で社会人になってから約1年と5ヵ月が経過しました。
エンジニアとして日々開発業務に追われていますが、少しずつ余裕が出てきました。
そこで、次のステップへ進むため私が開発に携わっているプロジェクトの改善作業に挑戦してみました!!
今回の改善作業は「プロジェクトに命名規則を導入させる」です。

命名規則(コーディング規約)とは  

まずそもそも命名規則とは?ですが、Wikipediaには

プログラミングを行う際にソースコード上の識別子(英: identifier)の名称となる文字列を決定するためのルールを定めたもの。ネーミング規則、ネーミング規約、あるいは命名規約とも呼ぶ。通常は、ソースコードの可読性や視認性の向上、プログラミング効率およびメンテナンス性の改善などを目的としている。

ウィキペディア 命名規則(プログラミング

と記載されています。
現在、私が携わっているプロジェクトでは約10名ほどのメンバーが開発をしています。
しかし、命名規則について明示的なルールが定まっていなかったので、命名については各メンバーが他の実装に合わせたり、本などで収集した情報や経験を元に名前をつけていました。
ですので、コードレビューの際に命名について指摘されることもありました。
そんな問題を改善するため今回は、typescript-eslint/naming-conventionを導入してみました。

1.命名規則策定

まずは、命名規則を検討するところから始めました。
今回使用するtypescript-eslint/naming-conventionでは、formatやselectorを指定し、自分でカスタマイズして作成できます。
最初は厳しめに「booleanのメソッドは必ず先頭に"is"を付ける」などの規則を検討してみましたが、「"has"や"exists"を使いたい場面がある」とメンバーからアドバイスをもらったり、厳しめのルールを導入してみた結果、違反数が多すぎて規則を適用しても無意味なことがありました。
そこで色々試行錯誤してみて、下記テーブルのようにselectorとformatの縛りになりました。

テーブル補足  

  • formatでは適用したい名付け規則を指定します。配列なので、複数指定可能です。()が付いているformatは、違反数が多すぎて許容にしたCaseです。将来的には禁止にしたいと考えています。

  • selectorでは、formatの適用対象を指定します。

  • 規制対象では、selectorの具体的な対象を載せています。表に載っていない規則対象もありますが、プロジェクトで使用していないので省略しています。例:variableにはvarも含まれています。

規制対象と適用フォーマット
.type.tsファイルの規制対象と適用フォーマット

formatに記載されているCaseについては、以下ルールがあります。

formatの説明

2.  「.eslintrc.js」にルールを追加

命名規則が策定できたらいよいよルールを導入します。
ルールの書き方は、naming-convention.mdを参考にしたら大体書けます。
1点苦戦したのが、特定のファイル(.type.tsまたは.type.js)に例外的なルールを導入したい時に、selectorとmodifiersが被ってしまうと、どちらかだけが適用されてしまう問題が発生しました。
※modifiersは、selectorのより細かい指定ができます。
下記NG例では、namingRulesとtypesNamingRulesのselectorがvaliableで、modifiersがconstになっています。
この場合、大きな括りのselectorは適用されますが、modifierのは適用されません。

    
NG例

/** 共通の命名規則 */
const namingRules = {
  '@typescript-eslint/naming-convention': [
    'warn',
    // ver,let,constはstrictCamelCaseを使用
    {
      'selector': 'variable',
      'format': ['strictCamelCase']
    },
    // constはStrictPascalCase,UPPER_CASEを許容
    {
      'selector': 'variable',
      'modifiers': ['const'],
      'format': ['strictCamelCase','StrictPascalCase','UPPER_CASE']
    },
  ]
}

/** typeファイルのrules */
const typesNamingRules = {
  '@typescript-eslint/naming-convention': [
    'warn',
    // constはUPPER_CASEを使用
    {
      'selector': 'variable',
      'modifiers': ['const'],
      'format': ['UPPER_CASE']
    }
  ]
}

{ 
  // tsファイルrules適用
  files: ['**/*.ts'],
  rules: namingRules
}

{ 
  // typeファイルrules適用
  files: ['**/*.type.ts'],
  rules: typesNamingRules
}

解決策としては、下記/** typeファイルのrules */のように、適用したい例外設定を始めに記載し、次に共通のルールを書くことで特定のルールも適用できました。

/**
 * 命名規則
 */
const commonWarnNamingRules = [
  // var,letはstrictCamelCaseを使用
  {
    'selector': 'variable',
    'format': ['strictCamelCase']
  },
  // constはstrictCamelCase,StrictPascalCase,UPPER_CASEを使用
  {
    'selector': 'variable',
    'modifiers': ['const'],
    'format': ['strictCamelCase','StrictPascalCase','UPPER_CASE']
  },
  // 関数はstrictCamelCaseを使用、先頭のアンダースコア許容
  {
    'selector': 'function',
    'format': ['strictCamelCase'],
    'leadingUnderscore': 'allow'
  },
  // get,setはstrictCamelCaseを使用
  {
    'selector': 'accessor',
    'format': ['strictCamelCase']
  },
  // 関数パラメーターはstrictCamelCaseを使用、先頭のアンダースコア許容
  {
    'selector': 'parameter',
    'format': ['strictCamelCase'],
    'leadingUnderscore': 'allow'
  },
  // typeはStrictPascalCase,UPPER_CASEを使用
  {
    'selector': 'typeAlias',
    'format': ['StrictPascalCase', 'UPPER_CASE']
  },
  // classはStrictPascalCaseを使用
  {
    'selector': 'class',
    'format': ['StrictPascalCase']
  },
  // interfaceはStrictPascalCaseを使用
  {
    'selector': 'interface',
    'format': ['StrictPascalCase']
  }
]

/** 共通命名rules */
const namingRules = {
  '@typescript-eslint/naming-convention': [
    'warn',
    ...commonWarnNamingRules
  ]
}

/** typeファイルのrules */
const typesNamingRules = {
  '@typescript-eslint/naming-convention': [
    'warn',
    // constはUPPER_CASEを使用
    {
      'selector': 'variable',
      'modifiers': ['const'],
      'format': ['UPPER_CASE']
    },
    ...commonWarnNamingRules
  ]
}

{ 
  // tsファイルrules適用
  files: ['**/*.ts'],
  rules: namingRules
}

{
  // typeファイルrules適用
  files: ['**/*.type.ts'],
  rules: typesNamingRules
}

あとは上記ruleを読み込むようにして命名規則の導入は完了しました!

導入後の結果は下記のようになります。
ちゃんと、constはUPPER_CASEを使うように警告が出ています。

.type.tsファイルのnaming-conventionによる警告

定数名をUPPER_CASEに修正すると、警告がなくなりました!
命名規則について、どのCaseを使うか教えてくれるのは便利です。

constの命名をUPPER_CASEに修正

以上が改善作業になります。

最後に

今回、命名規則の導入を行ってみて、設定系のファイルを編集することが無かったので良い経験になりました。
また、現在の運用方針を見直すきっかけになれたと思います。
今回は基本的な命名規則しか作れなかったので、将来的には特定の単語を禁止にしたり、ルールを作らなくても命名規則が合うようにしていきたいです。

おまけ

今回naming-conventionを導入した際に、どれくらい警告数が出ているか気になったので、eslint-nibbleで計測を行いました。
eslint-nibbleでは、導入したルールの警告数や違反数が、どのファイルで出ているのか特定できるので、非常におススメです!!

eslint-nibble使用例

採用情報

イベント情報

この記事が気に入ったらサポートをしてみませんか?