三元表达式的奇妙案例
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
三元表达式的格式化始终是个难题,我们终于在 v3.1.0 版本中引入全新的格式化方案来解决这个问题。
本文将带您了解我们的探索历程、变革动机,以及早期开发者反馈和"奇妙三元表达式"风格的概览。
欢迎试用 --experimental-ternaries 选项并分享您的使用体验!
快速了解要点,请参阅发布说明。
引言
在各种复杂场景中优雅地格式化嵌套三元表达式,竟是出人意料的技术挑战。
长期以来,开发者们因难以理解嵌套三元表达式,最终往往将其重构为丑陋的 if-else 语句串,通常伴随着 let 声明、立即执行函数或独立函数。
据测试者反馈,我们开发的新格式化风格可能需要适应期,但最终能让三元表达式在现代代码库中真正成为简洁的 if-else 表达式替代方案。
历史背景
Prettier 最初采用的简单粗暴方案——单纯为嵌套三元表达式的每一层添加缩进——在简单场景下表现尚可,但显然无法适应长嵌套链,且存在其他问题。
因此在 2018 年,我们改用扁平化三元表达式,当时看似明智之举,却反响不佳——要求回退的议题获得了超 500 次支持。
尽管最终回归了缩进式三元表达式,我们仍希望找到更优方案。
过去几年间,我们探索了众多可能方案,力求在常见场景保持缩进式的可读性,同时适应更复杂的应用场景。
严苛标准
理想方案需满足以下标准:
-
任何情况下都能清晰辨识「
if条件」、「then结果」和「else结果」的对应关系 -
代码排版应自然过渡:从单个三元式 → 双链式 → 长链简单案例 → 含嵌套条件的复杂结构(多数方案未通过此测试)
-
JSX、TypeScript条件表达式(无法用
if实现)和常规JS的语法应保持视觉一致性 -
能适应任意长度的嵌套链(例如含数十个分支的TypeScript条件类型)
缩进式方案明显未达标(4),在(1)上也存疑,甚至(3)——我们虽常将JSX三元式处理为扁平可读格式,但该格式在JSX之外显得生硬。
社区中有许多人曾对“case风格”表示期待,这种风格借鉴了Rust或OCaml等语言的match语法,但它未能满足第(2)条标准以及其他目标。
出人意料的解决方案
好消息是我们找到了满足所有标准的格式化算法;坏消息是这种算法非常新颖,对大多数开发者来说还很陌生。
在Beta测试阶段,我们发现开发者首次接触时普遍持怀疑态度:

但在短暂使用后,他们却不愿再回到旧版:

另一位开发者这样评价:
启用新规则的第一小时感觉有些奇怪。但到第二小时,我已经多次用它解决了原本需要改用丑陋
if语句重构的问题。我不想再回去了。
我曾厌恶嵌套三元表达式,但更讨厌将简洁的代码重构成
if-else语句。新规则为语言增加了可理解的、线性化的if-else,if-else表达式,比多重嵌套分支的三元表达式优雅得多。
因此我们确信找到了最佳方案,但也意识到这可能给社区带来冲击。
为此,我们决定将新格式放在临时的--experimental-ternaries选项下进行数月测试,同时先发布社区呼声已久的缩进式三元表达式。
样式概览
这种新样式究竟长什么样?
以下通过精简示例展示"新奇三元表达式"的设计逻辑:
const animalName =
pet.canBark() ?
pet.isScary() ?
'wolf'
: 'dog'
: pet.canMeow() ? 'cat'
: 'probably a bunny';
-
以问号结尾的行代表 "if"条件
- 看到
foo ?就像在询问关于foo的条件——"如果foo成立?那么..."
- 看到
-
以
:开头的行代表 "else"分支- 看到
: foo表示"否则返回foo" - 看到
: foo ?表示"否则如果foo成立?"
- 看到
-
不含
:或?的行代表 "then"。- 看到
foo表示"那么返回foo"
- 看到
改写后的代码展示"case风格"三元表达式:
const animalName =
pet.isScary() ? 'wolf'
: pet.canBark() ? 'dog'
: pet.canMeow() ? 'cat'
: 'probably a bunny';
可见这是用普通三元运算符在JavaScript中实现类match语法的简洁方案(尽管缺少某些功能)。
我们的新格式融合了"新奇三元表达式"(问号始终在行尾)与"case风格"(问号在行中)的优势。
例如:
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
