Semicolons
Prettierにおけるセミコロン(Semicolons)
Prettierは、コードのフォーマットを自動的に行ってくれるツールであり、その目的はチーム内での一貫したコーディングスタイルを強制し、コードレビューの時間を短縮することです。Prettierにはいくつかの設定オプションがありますが、その中でも特に議論の対象となるのが「セミコロン(Semicolons)」に関する設定です。
JavaScriptでは、通常、文の終わりにはセミコロンを付けることが推奨されます。しかし、JavaScriptには「Automatic Semicolon Insertion (ASI)」という機能があり、一部のケースではセミコロンがなくてもJavaScriptエンジンが自動的に補完してくれます。このため、セミコロンを省略するスタイルも存在します。
Prettierには、このセミコロンの有無に関する設定オプションがあり、デフォルトではセミコロンを付与するようになっています。この設定はsemi
というオプションで制御されます。
semi: false
: 可能な限りセミコロンを省略します。ただし、ASIの誤作動を防ぐために、セミコロンが必要な場合は付与されます。semi: true
(デフォルト): 文の終わりに常にセミコロンを付与します。
- 一貫性
チーム全体でセミコロンの有無に関するルールを決めることで、コードベース全体の一貫性を保つことができます。これにより、複数の開発者がコードを修正する際に、スタイルが混在するのを防ぎます。 - 可読性
セミコロンの有無は、コードの可読性に影響を与えることがあります。セミコロンを付けることで、どこで文が終わるかが明確になり、コードが読みやすくなるという意見もあります。一方、セミコロンを省略することで、よりクリーンで簡潔なコードになるという意見もあります。 - ASIの落とし穴
ASIは便利な機能ですが、意図しない挙動を引き起こす「落とし穴」も存在します。例えば、特定の条件下で改行されたコードが予期せず結合されてしまい、バグにつながることがあります。semi: true
に設定することで、このASIによる潜在的な問題を回避できるというメリットがあります。
Prettierにおけるセミコロンの一般的なエラーとトラブルシューティング
Prettier はコードのフォーマットを自動化する非常に便利なツールですが、セミコロンの設定に関しては、特に他のツール(ESLintなど)との連携において問題が発生することがあります。
一般的なエラーと問題
-
semi: false
に設定しているのにセミコロンが追加される。semi: true
に設定しているのにセミコロンが削除される。- これは、Prettier の設定が正しく適用されていないか、他のフォーマッターやリンター(特に ESLint)との競合が原因であることがほとんどです。
-
ESLint との競合
- Prettier でフォーマットしたのに ESLint がセミコロンのエラーを出す。
- ESLint のルールと Prettier の設定が異なる場合に発生します。例えば、Prettier がセミコロンを省略する設定になっているのに、ESLint の
semi
ルールがセミコロンを必須としている場合などです。
-
保存時にフォーマットされない、または一貫性がない
- ファイルを保存しても Prettier が期待通りに動作しない。
- セミコロンの有無が一貫しない(あるファイルでは付くのに、別のファイルでは付かない)。
- これは、VS Code などのエディタ設定やプロジェクトの Prettier 設定の適用順序に問題がある可能性があります。
-
コードが壊れる、または予期せぬ挙動
- ごく稀に、特定の複雑なコード(特にコメントを含むアロー関数など)で、Prettier が不正なセミコロンを追加したり削除したりして、コードが構文エラーになることがあります。これは Prettier のバグである可能性が高いです。
セミコロンに関する問題を解決するために、以下のステップを試してください。
-
Prettier の設定ファイルを確認する (.prettierrcなど)
- プロジェクトのルートに
.prettierrc
(またはprettier.config.js
、package.json
のprettier
フィールドなど) が存在するか確認します。 - そのファイル内に
semi
オプションが正しく設定されているかを確認します。// 例: セミコロンを常に付与する場合 { "semi": true } // 例: 可能な限りセミコロンを省略する場合 { "semi": false }
- もし、この設定ファイルがない場合は、作成してください。
- プロジェクトのルートに
-
エディタ(VS Codeなど)の設定を確認する
- VS Code の場合
settings.json
を開きます (Ctrl + , で設定を開き、右上にある{}
アイコンをクリック)。"editor.formatOnSave": true
が有効になっていることを確認します。"editor.defaultFormatter"
がesbenp.prettier-vscode
に設定されていることを確認します。- ワークスペース固有の設定 (
.vscode/settings.json
) が、グローバル設定やプロジェクトの.prettierrc
を上書きしていないか確認します。 "prettier.semi"
という設定が直接settings.json
に記述されている場合、これが.prettierrc
の設定を上書きしている可能性があります。可能であれば、.prettierrc
で一元管理し、エディタ側のprettier.semi
は削除するか、未設定のままにすることをお勧めします。
- VS Code の場合
-
他の拡張機能との競合を調べる
- VS Code などで、Prettier 以外にもコードフォーマットを行う拡張機能(例えば、ESLint のみがフォーマットを行う設定になっている、別の言語固有のフォーマッターなど)をインストールしている場合、それらが Prettier の動作を妨げている可能性があります。
- 一時的に他のフォーマット関連の拡張機能を無効にして、問題が解決するかどうか確認してみてください。
-
Prettier 関連のキャッシュをクリアする
- 稀に、Prettier のキャッシュが原因で問題が発生することがあります。プロジェクトの
node_modules/.cache/prettier
ディレクトリを削除してから、再度 Prettier を実行してみてください。
- 稀に、Prettier のキャッシュが原因で問題が発生することがあります。プロジェクトの
-
Prettier のバージョンを確認する
- 古い Prettier のバージョンを使用している場合、最新の機能やバグ修正が適用されていない可能性があります。最新バージョンにアップデートしてみてください。
-
prettier --check と prettier --write を試す
- ターミナルで
npx prettier --check .
を実行し、どのファイルがフォーマットルールに準拠していないかを確認します。 npx prettier --write .
を実行して、すべてのファイルを強制的にフォーマットし直します。これにより、どこで問題が発生しているのかのヒントが得られることがあります。
- ターミナルで
Prettierのセミコロン設定に関するコード例
Prettier の設定は、通常、プロジェクトのルートディレクトリに配置された .prettierrc
ファイル(または package.json
の prettier
フィールドなど)で行います。
設定ファイル例: .prettierrc
(JSON形式)
// セミコロンを常に付与する設定(Prettierのデフォルト)
{
"semi": true
}
// 可能な限りセミコロンを省略する設定
{
"semi": false
}
semi: true
の場合の例 (セミコロンを常に付与)
Prettier 適用前のコード
const message = "Hello, world"
console.log(message)
function greet(name) {
return "Hello, " + name
}
const add = (a, b) => a + b
const result = add(10, 20)
console.log(result)
semi: true で Prettier を適用した後のコード
const message = "Hello, world";
console.log(message);
function greet(name) {
return "Hello, " + name;
}
const add = (a, b) => a + b;
const result = add(10, 20);
console.log(result);
解説:
semi: true
の場合、各文の最後にセミコロンが追加されます。これはJavaScriptの伝統的なスタイルであり、Automatic Semicolon Insertion (ASI) の潜在的な問題を回避するためにも推奨されることが多いです。
semi: false
の場合の例 (可能な限りセミコロンを省略)
Prettier 適用前のコード
const message = "Hello, world";
console.log(message);
function greet(name) {
return "Hello, " + name;
}
const add = (a, b) => a + b;
const result = add(10, 20);
console.log(result);
// ASIの挙動に影響を与える可能性があるコード
const val = 10
;[1, 2, 3].forEach(n => console.log(n)) // この行の先頭のセミコロンは必要
semi: false で Prettier を適用した後のコード
const message = "Hello, world"
console.log(message)
function greet(name) {
return "Hello, " + name
}
const add = (a, b) => a + b
const result = add(10, 20)
console.log(result)
// ASIの挙動に影響を与える可能性があるコード
const val = 10
;[1, 2, 3].forEach(n => console.log(n)) // この行のセミコロンは残る(または追加される)
解説:
semi: false
の場合、JavaScriptのASI機能によってセミコロンがなくても問題ない箇所ではセミコロンが省略されます。ただし、ASIの誤作動を引き起こす可能性がある場合(例えば、(
や [
で始まる行が前の行の文と結合されてしまうようなケース)では、Prettierは安全のためにセミコロンを付与します。
上記の例でいうと、const val = 10
の後の行が [
で始まっているため、もしセミコロンがないと 10[1, 2, 3]...
のように解釈されてエラーになります。そのため、Prettier はこの部分に自動的にセミコロンを追加、または残します。
semi: false
を選択する際に知っておくべき、ASIが関わる典型的な「落とし穴」の例です。
ASIにより意図しない挙動になる可能性のあるコード例(セミコロンがない場合)
function getValue() {
return // ここで改行
{
a: 1
}
}
console.log(getValue()) // undefined が出力される可能性がある
このコードは、JavaScriptエンジンによって以下のように解釈される可能性があります。
function getValue() {
return; // ここでセミコロンが自動挿入される
{
a: 1
}
}
console.log(getValue()) // undefined が出力される
return
文の後に改行があるため、ASIによって return;
と解釈され、関数は何も返さずに終了してしまいます。結果として undefined
が返されます。
Prettierがこの種の危険を回避する例 (semi: false の場合でも)
Prettier は、上記のような ASI の危険な挙動を引き起こす可能性のあるコードに対しては、たとえ semi: false
であっても、セミコロンを付与したり、適切なフォーマットを行うことで安全性を確保しようとします。
もし、上記のようなコードを意図的に書く場合は、semi: true
にするか、または {
を return
と同じ行に書くなど、明示的にセミコロンを付けるか、ASI のルールを理解してコードを記述する必要があります。
// セミコロンがない場合の安全な書き方(Prettierが推奨する形式)
function getValue() {
return {
a: 1
}
}
console.log(getValue()) // { a: 1 } が出力される
Prettier の semi
オプションは、プロジェクトのコーディングスタイルと、JavaScriptのASIに関する理解に基づいて選択すべきです。
- "semi": false
可能な限りセミコロンを省略する、よりミニマルなスタイルです。Prettier はASIの危険なケースを自動的に検知してセミコロンを挿入しますが、開発者自身もASIのルールをある程度理解している方が安全です。 - "semi": true (デフォルト)
各文の終わりに明示的にセミコロンを付与する、より安全で伝統的なスタイルです。ASIによる予期せぬ挙動を完全に回避したい場合に適しています。
Prettier は意図的に設定オプションを少なくすることで、フォーマットに関する議論を減らすことを目指していますが、セミコロンの有無は非常に意見が分かれるスタイルであるため、semi
オプションが提供されています。したがって、Prettier 内で「セミコロンの挙動を変える」代替方法としては、基本的にこの semi
オプションを切り替えることになります。
ここでは、Prettier の semi
オプション以外の文脈で、「セミコロンに関するプログラミングの代替方法」として考えられることをいくつかご紹介します。
PrettierとESLintの連携による制御
これは最も一般的な「代替方法」であり、Prettier の semi
オプションに加えて、ESLint のルールを使ってセミコロンの挙動をより厳密に制御する方法です。
考え方
- ESLint はコードの品質(バグの可能性、スタイルの逸脱など)をチェックする。
- Prettier はコードのフォーマットを担当する。
セミコロンの有無は、フォーマットと品質の両方に関わるため、両方のツールで設定を調整する必要があります。
設定例
プロジェクトの .prettierrc
ファイルで semi
を設定します。
// .prettierrc
{
"semi": false // セミコロンを省略する
}
次に、ESLint の設定ファイル(例: .eslintrc.js
または .eslintrc.json
)で、ESLint が Prettier のフォーマットと競合しないように設定します。
-
eslint-config-prettier の使用
これは、Prettier のルールと競合する ESLint のフォーマット関連ルールを無効にするための設定です。これを ESLint のextends
の最後に記述します。// .eslintrc.js module.exports = { extends: [ // 他のESLint設定(例: 'eslint:recommended', 'airbnb' など) 'prettier' // これを一番最後に記述する ], rules: { // Prettier のセミコロン設定に合わせるESLintのルール // Prettierでセミコロンを省略する場合(semi: false) 'semi': ['error', 'never'], // 'no-unexpected-multiline' は、ASIの落とし穴を検出するために推奨される 'no-unexpected-multiline': 'error' } };
解説:
eslint-config-prettier
は、ESLint のsemi
ルール自体を直接設定するわけではありません。これは、Prettier のsemi: false
とは異なり、ESLint 側で「セミコロンがないことを強制する」ためのルール ('semi': ['error', 'never']
) を明示的に追加する必要があります。同時に、ASI の「落とし穴」による潜在的な問題を ESLint が検出できるように、no-unexpected-multiline
のようなルールを有効にしておくことが強く推奨されます。
コードスタイルの強制ツール(Prettier以外の選択肢)
もし Prettier の提供する semi
オプションだけでは不十分だと感じたり、より柔軟なセミコロンの制御(またはより厳格なゼロ設定ポリシー)を求める場合、Prettier 以外のコードスタイル強制ツールを検討することも「代替方法」と言えます。
-
EditorConfig
Prettier や ESLint のようなツールではありませんが、エディタレベルで基本的なコードスタイル(インデントの種類、サイズ、行末の改行など)を統一するためのファイル形式です。.editorconfig
ファイルをプロジェクトに配置することで、異なるエディタを使っている開発者間でも基本的なフォーマットルール(セミコロンの有無は直接制御しない)を共有できます。これは Prettier や ESLint と組み合わせて使用されることが多く、それぞれが異なるレベルでコードスタイルを強制する役割分担となります。 -
ESLint単体での使用
Prettier のようなフォーマッターを使わず、ESLint のみでフォーマットとリンティングの両方をカバーすることも可能です。ESLint は非常にカスタマイズ性が高く、semi
ルールを含むあらゆるフォーマット関連ルールを細かく設定できます。しかし、Prettier のように「コードを再構築してきれいに整形する」能力は限定的で、主にルール違反を指摘・修正する用途に特化しています。大規模なコードベースや、Prettier では実現できない非常に特殊なフォーマットルールが必要な場合に検討されますが、通常は Prettier との併用が推奨されます。設定例(
.eslintrc.js
のみ):module.exports = { rules: { 'semi': ['error', 'always'], // 常にセミコロンを必須にする // または // 'semi': ['error', 'never'], // セミコロンを禁止する(ASIの安全ルールは別途必要) 'indent': ['error', 2], // インデントをスペース2つにする 'quotes': ['error', 'single'], // シングルクォートを必須にする // ... 他のフォーマット関連ルールもESLintで設定 } };
-
StandardJS
「セミコロンなし」をデフォルトとする、非常に厳格なゼロコンフィグのJavaScriptスタイルガイドです。StandardJSは、ESLintのルールを内部で利用しており、セミコロンの自動挿入を前提とした安全なコーディングスタイルを強制します。Prettier のようにカスタマイズ性が低いですが、チーム全体で厳密に「セミコロンなし」を強制したい場合に有効な選択肢です。特徴:
- セミコロンなし
デフォルトでセミコロンを使いません。 - ゼロコンフィグ
ほとんど設定不要で始められます。 - 厳格なスタイル
細かな部分までスタイルが決められています。
- セミコロンなし
これは「代替方法」というよりは「注意点」ですが、JavaScriptのASIの挙動を理解し、セミコロンがなくても安全に動作するようにコードを記述することです。semi: false
を使っている場合に特に重要になります。
例
// 悪い例(ASIの落とし穴の可能性)
const data = getData()
;[1, 2, 3].forEach(item => console.log(item)) // 意図せずセミコロンを省略すると、前の行と結合される可能性
// 良い例(セミコロンなしでも安全な書き方)
const data = getData() // ここで文が終わっていることが明確
// 新しい行で配列が始まるため、ASIが正しく機能する
;[1, 2, 3].forEach(item => console.log(item))
または、以下のように書くことで、セミコロンがなくても安全になります。
const data = getData()
const items = [1, 2, 3]
items.forEach(item => console.log(item))