Zenn
🚫

TS/JSでセミコロンをつけないスタイル(No-Semi)について

2025/02/24に公開
9
18

TypeScriptやJavaScriptにおいて、文末にセミコロンをつけないスタイル(以下「No-Semiスタイル」)の現在の普及状況について、最近の調査資料が見つからなかったため、独自に調べてみました。コーディングスタイルを検討する際の参考になれば幸いです。

背景

Cursor ComposerやClineなどのコーディングAIを使ってTypeScriptの開発をしていると、Lint設定でNo-Semiスタイルを指定しているにもかかわらず、Composerがセミコロンありのコードを生成してしまうため、毎回Lintエラーが発生することがあります。

この問題は「TypeScriptではNo-Semiスタイルを採用する」とカスタムプロンプトに明記することで回避可能です。しかし、デフォルトのスタイルとしてセミコロンありが採用されていることには少し違和感がありました。

いつからかは定かではありませんが、私自身はTypeScriptやJavaScriptを書く際には自然とNo-Semiスタイルをとるようになっています。周りのプログラマにヒアリングしてみても、TypeScriptでNo-Semiスタイルを採用しているケースは少なくありません。

この背景には、最近のWeb開発スタックにNo-Semiスタイルが多く取り入れられていることがあると考えられます。たとえば以下のようなプロジェクトでは、公式ドキュメントのコード例にセミコロンがないものを目にします。

Next.js / Prisma / Supabase

以下はNext.jsの公式サイトのサンプルです。

export default async function Page() {
  const data = await fetch('https://api.vercel.app/blog')
  const posts = await data.json()
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

少し調べてみると、JavaScriptコミュニティ全体としては「セミコロンを付ける/付けないは好みの問題」という認識が定着しているようです。しかし、具体的にどれくらいNo-Semiスタイルが採用されているのか、あるいは増加傾向にあるのかを示すような調査はあまり見当たりませんでした。

そこで本記事では、No-Semiスタイルの発生と普及、これまでの議論を簡単にまとめるとともに、実際の採用率に関する調査結果をご紹介します。

No-Semiスタイルの発生と普及

JavaScriptは文末に必ずしもセミコロンを必要としません。これは「自動セミコロン挿入(ASI)」と呼ばれる仕様によるもので、必要な箇所にはインタプリタが自動的にセミコロンを補完します。このため、意図的に文末のセミコロンを省略するNo-Semiスタイルが登場し、賛否両論ありつつも徐々に受け入れられてきました。

1997年の初版から続くECMAScript/JavaScriptの仕様においては、基本的に文末のセミコロンは任意です。改行によって文の終了が認識される場合、JavaScriptエンジンは自動的にセミコロンを挿入してくれるため、JavaScriptでは当初からセミコロンは「省略可能」でした。

一方で、長い間JavaScriptコミュニティでは「セミコロンを常につける」スタイルが主流でした。Googleのスタイルガイドをはじめ、影響力のあるガイドラインが「セミコロンあり」を推奨していた影響も大きいと思われます。

しかし、2010〜2012年ごろから一部の開発者が「ほとんどの場合、セミコロンは省略できる」と主張し始めました。StackExchangeなどで熱い議論が交わされましたが、最終的にはNo-Semiスタイルが実験的な流行から主要プロジェクトでも採用される「有力なスタイルのひとつ」へと成長していきます。

No-Semiスタイルの台頭には、以下のような要因が関係していると考えられます。

1. 開発エコシステムの成熟

以前は文末にセミコロンを付けなければ誤動作を引き起こすツール(たとえばUglifyJSの初期バージョンなど)も存在しました。しかし、現在のJavaScriptエコシステム全体が成熟するにつれ、こうしたツールは改善されたり淘汰されていきました。これによって「バグを防ぐためにセミコロンをつけるべきだ」という主張の根拠は弱くなりました。

2. StandardJS

2015年に登場したZero ConfigurationのLinterであるStandardJSは、デフォルトでセミコロンを付けないルールを採用しています。これをきっかけに、多くのNode.jsやオープンソースプロジェクトがNo-Semiスタイルを意識するようになりました。

3. Prettier

2017年に登場したPrettier(コードフォーマッター)は、設定次第でセミコロンの有無を自動で処理できます。これによって「セミコロンを付ける/付けない」の議論そのものがツールの設定で完結するようになり、スタイル選択の自由度が高まりました。

4. TypeScriptの影響

TypeScriptはJavaScriptのスーパーセットで、ASIもそのまま利用できるためセミコロンは必須ではありません。さらにTypeScriptのコンパイラが改行による意図しない挙動(例:returnとオブジェクトリテラルを改行して書くケース)を検知しやすくすることもあり、No-Semiスタイルを安心して採用できる下地が整っています。

現在のNo-Semiの普及率調査

TypeScript/JavaScriptを使ったGitHubの人気リポジトリを対象に、PrettierのNo-Semi設定(semi: false)を採用している割合を調べました。期間はPrettierが一般に認知され始めた2017年以降で、TypeScript・JavaScriptそれぞれスター数の多い上位100プロジェクトをリストアップし、Prettierの設定ファイルを確認できたものを対象としています。

調査結果は以下のとおりです。(調査日:2025年2月24日)

言語 Repos Prettier採用数 Semi No-Semi 普及率
TypeScript 100 90 72 18 20.0%
JavaScript 100 70 65 5 7.1%
合計 200 160 137 23 14.4%

上記を見ると、TypeScriptのほうがNo-Semiスタイルの採用率は高く、20%ほどがNo-Semiを設定していました。一方でJavaScriptでは約7%にとどまっており、総合では14.4%がNo-Semiを選択しているという結果でした。

まとめ

  • JavaScriptはもともと自動セミコロン挿入(ASI)を備えており、セミコロンは必須ではない
  • 近年、標準LintとしてのStandardJSやコードフォーマッターのPrettierが普及したことで、No-Semiスタイルを含む多様なコーディングスタイルが採用されやすくなった
  • TypeScriptでもNo-Semiスタイルは有力な選択肢のひとつとして定着しつつあり、人気プロジェクトの2割ほどで採用されている

No-Semiスタイルはセミコロン不要でコードがスッキリするといった利点がある一方、好みやチームの方針、他のツールやコンベンションとの整合性などを踏まえる必要があります。

No-SemiかSemi付きかにはコミュニティにおいては「好みの問題である」という結論が出ていることを前提に、最終的にはプロジェクトやチームの合意のもとでスタイルを決め、PrettierやESLintなどのツールで一貫性を保つのが望ましいでしょう。

18
Sparkle AIブログ

Discussion

クロパンダクロパンダ

TSでのno-semi、確かになと思って読んでました。事前にシンタックスがチェックされるのでセミコロンつけないことで起きる諸問題も回避できますし、トランスパイルもされるので。

ただ、JSのほうは以前semiのほうが良いんじゃないかなと思いました。静的型検査されないので 諸問題 が起きる可能性があります。
そもそも、TSがない時代のJSにおいてセミコロン派が主流だったのは、自分のJSスクリプトのあとに実行されるJS、前に実行されたJSの影響を受ける可能性がある、というのも理由の一つだったと思います。(const x = someFunc() のあとに (function(){})() が読み込まれるとエラーになるなど)

いまは各バンドラ、ビルドツール側である程度配慮されているはずだから問題は減ったとはいえ、上にあげた問題をすべては回避できないので、JSに関してはつけたほうが楽なんじゃないかなと思いました。

あいや - aiya000あいや - aiya000

蛇足ですが、弊社Nuxt(TypeScript)テンプレートの前身では

const x = someFunc()
(function(){})()

していると、以下に自動整形されていた気がします。

const x = someFunc()
;(function(){})()

eslintでも自動フォーマットさせていたので、いずれかのルールがやってくれていたのかもしれません。

参考までに、現行の弊社Nuxt(TypeScript)テンプレートを上げておきます。
ただしまだ開発中であり、自動フォーマット周りが怪しいので、上記のフォーマットはしてくれないかもしれません。
https://github.com/PublicHIKKY/vket-boilerplate-nuxt

culageculage

例えばここに No-Semi スタイルで書いた分割代入のサンプルコードがある。

let a, b, c
a = "hoge";                     // 通常の代入
[b, c] = ["fuga", "piyo"]       // 分割代入
console.log(a, b, c)            // 結果出力 "hoge", "fuga", "piyo"

おやおや、スタイルに反して「通常の代入」行にセミコロンが混入していますよ……と思ってセミコロンを削除するとこのコードは正しく動作しなくなる。
No-Semi スタイルでも、このセミコロンは必須である。
(セミコロンが無いと「a = "hoge"[b, c] = ["fuga", "piyo"]」だと解釈されるので)

もちろん、こんな問題があるという議論も尽くされた末にNo-Semiスタイルが導入されてきたんだろうけれど、そんな気軽に選択していいスタイルじゃないと思う。

フシハラフシハラ

処理の区切りで絶対書き間違いがあるから想像も出来ないけど、tsで20%も採用しているのは驚き。

rithmetyrithmety

今時のプロジェクトは Git を使ってますね
そしてセミコロンのあるコードは Git との相性が悪いです

no-semi は true であるべきで trailing-comma も同様に all の方が良いですし
ファイルの末尾には改行が入っているべきです

  obj.hoge()
-   .fuga(); // 不要な diff が出てしまう 邪魔で読みづらい
+   .fuga()
+   .piyo();

個人的にはセミコロン無しでの意図しないコードの検出は TypeScript よりも Prettier のようなフォーマッタの貢献が大きいと思います
たとえば下記のようなコードはフォーマッタをかければ明らかに意図しないコードになって気づけるか、あるいは正しく修正されます

let a = []
[b, c] = d

私が知る限りでもセミコロン要らない派の意見はどれも古いプロジェクトでしか役に立たないものばかりに感じますし
セミコロンを入れていたためにおこるバグもありますね…

// 新しく div を追加しました!
return <div>
  <span>hello, world</span>;
</div>;
mikamika

セミコロンは多くのプログラマの時間を無駄にしキーボードの寿命を奪ってきた悪魔だと思っています

mashuelmashuel

我が流派では不要な所(改行削除しても影響皆無)だけ積極的に省略

ログインするとコメントできます