メインコンテンツへスキップ

奇妙な三項演算子の考察

· 1分で読める
非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

三項演算子のフォーマットは常に課題でしたが、v3.1.0で新たなフォーマットスタイルを導入し、ついに解決に取り組みます。

この変更に至るまでの道のりと背景、開発者からの初期フィードバック、そして「奇妙な三項演算子」スタイルの概要について読み進めてください。

ぜひ --experimental-ternaries オプションをお試しいただき、ご意見をお聞かせください!

手短な要約はリリース記事をご覧ください。

導入

多様なシナリオでネストされた三項演算子を適切にフォーマットすることは、驚くほど難しい課題です。

開発者は長年、三項演算子の可読性の低さに悩まされ、最終的には let 宣言や即時関数、独立した関数を伴う if-else 文の冗長な連鎖へリファクタリングするケースが頻繁に見られました。

ベータテスターによれば、新たに開発したフォーマットスタイルには多少の慣れが必要ですが、最終的には現代的なコードベースで if-else 式の簡潔な代替として実用的に活用できるようになります。

歴史的背景

Prettierの初期の単純なアプローチ(ネストされた三項演算子の各レベルにインデントを追加する)は単純なケースでは機能しましたが、長いチェーンには明らかにスケールせず、他の問題も抱えていました。

そこで2018年にフラットな三項演算子フォーマットへ置き換えました。当時は良案のように思われましたが、評判は芳しくなく、元に戻すことを求めるIssueは500以上の賛成票を集めました。

最終的にインデント付き三項演算子へ戻しましたが、より良い方法を模索し続けました。

過去数年かけて、一般的なケースではインデント付き三項演算子と同等の可読性を保ちつつ、より多様な状況でも機能する解決策を数多く探求し実験を重ねました。

困難な要件

理想的な解決策は以下の基準を満たすものです:

  1. あらゆるケースで「if」「then」「else」の各要素とその対応関係が追跡しやすいこと

  2. 単一の三項演算子から2連鎖、単純ケースの長い連鎖、ネストされた複数条件まで、コードが自然に流れること(検討した代替案の多くはこのテストに失敗)

  3. JSX、TypeScriptの条件式(ifでは表現不可)、通常のJavaScriptで構文の見た目と操作性が統一されていること

  4. 任意の長さのネストされた三項演算子チェーンに対応可能なこと(数十の選択肢を持つTypeScriptの条件型を想像してください)

インデント付き三項演算子は明らかに基準(4)を満たせず、(1)もおそらく達成できず、(3)についてもJSX外では不自然に感じられるフラットな形式をほぼ常に採用していました。

コミュニティの多くの人々が「ケーススタイル」に期待を寄せていました。これはRustやOCamlなどの言語のmatch構文に着想を得たものでしたが、(2)やその他の目標を満たせませんでした。

驚くべき解決策

良いニュースは、私たちの基準を満たす書式設定アルゴリズムを見つけたことです。悪いニュースは、それが斬新なため、ほとんどの開発者にとって馴染みのないものだということです。

この機能のベータテストでは、開発者は初めてそれを見たとき非常に懐疑的でした:

"ここでは新しいバージョンの方が読みやすいとは思えません。"

しかし、しばらく使ってみると、戻りたくなくなったのです:

"三項演算子が気に入りました!このようにフォーマットするのは理にかなっていると思います。また、かなり早く慣れることができました。\n同感です。慣れるのに時間はほとんどかかりません。"

別の開発者はこう述べています:

ルールを有効にした最初の1時間は、少し奇妙に感じました。しかし2時間後までには、if文へのリファクタリングという見苦しい方法でなければ解決できなかった問題を、この方法で数回解決していました。もう戻るつもりはありません。

以前はネストされた三項演算子が嫌いでしたが、きれいな1行のコードをif-else文に書き換えるのも嫌でした。新しいルールは、言語に理解しやすい直線的なif-elseif-else式を追加し、ネストされた分岐として複数の三項演算子を使うよりもずっと優れています。

こうして私たちは勝ちパターンを見つけたと感じましたが、コミュニティにとっては衝撃的な導入となる可能性があることも認識していました。

その結果、私たちはこの新しい書式を一時的な--experimental-ternariesオプションの後ろに数ヶ月間置くことに決め、その間、コミュニティが切望していたインデントされた三項演算子をリリースすることにしました。

スタイルの概要

では、この新しいスタイルは一体どのようなものなのでしょうか?

「キュリアス」な三項演算子の背後にある考え方を示すために、簡単な作為的な例を次に示します:

const animalName =
pet.canBark() ?
pet.isScary() ?
'wolf'
: 'dog'
: pet.canMeow() ? 'cat'
: 'probably a bunny';
  1. 疑問符で終わる行はすべて "if"(条件)です。

    • foo ?を見たら、fooについて質問しているようなもの – 「fooなら? その場合…」という感じです。
  2. :で始まる行はすべて "else"(それ以外の場合)です。

    • : fooは「それ以外の場合、foo」を意味します。
    • : foo ?は「それ以外の場合、fooなら?」を意味します。
  3. :?がない行は "then"(その場合の結果)です。

    • 単にfooとある場合は、「その場合、foo」を意味します。

そして、ここに「ケーススタイル」の三項演算子を示すために書き直したコードがあります:

const animalName =
pet.isScary() ? 'wolf'
: pet.canBark() ? 'dog'
: pet.canMeow() ? 'cat'
: 'probably a bunny';

これは、控えめな三項演算子(いくつかの機能は欠けていますが)を使って、JavaScriptでmatchスタイルの構文に近いものを得る素晴らしく簡潔な方法だとわかります。

私たちの新しい書式は、「キュリアス」な三項演算子(疑問符が常に行の末尾にある)と「ケーススタイル」の三項演算子(疑問符が行の途中にある)を流動的にブレンドしたものです。

例:

const animalName =
pet.canSqueak() ? 'mouse'
: pet.canBark() ?
pet.isScary() ?
'wolf'
: 'dog'
: pet.canMeow() ? 'cat'
: pet.canSqueak() ? 'mouse'
: 'probably a bunny';

フィードバックをお寄せください!

より読みやすい新しいデフォルトを気に入っていただければ幸いです。そして、新しい --experimental-ternaries オプションを数週間試して、ご意見を ぜひ お聞かせください。

Googleフォームからフィードバックをお寄せください: https://forms.gle/vwEuboCobTVhEkt66