跳至主内容区

三元表达式的奇妙案例

· 1 分钟阅读
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

三元表达式的格式化始终是个难题,我们终于在 v3.1.0 版本中引入全新的格式化方案来解决这个问题。

本文将带您了解我们的探索历程、变革动机,以及早期开发者反馈和"奇妙三元表达式"风格的概览。

欢迎试用 --experimental-ternaries 选项并分享您的使用体验!

快速了解要点,请参阅发布说明

引言

在各种复杂场景中优雅地格式化嵌套三元表达式,竟是出人意料的技术挑战。

长期以来,开发者们因难以理解嵌套三元表达式,最终往往将其重构为丑陋的 if-else 语句串,通常伴随着 let 声明、立即执行函数或独立函数。

据测试者反馈,我们开发的新格式化风格可能需要适应期,但最终能让三元表达式在现代代码库中真正成为简洁的 if-else 表达式替代方案。

历史背景

Prettier 最初采用的简单粗暴方案——单纯为嵌套三元表达式的每一层添加缩进——在简单场景下表现尚可,但显然无法适应长嵌套链,且存在其他问题

因此在 2018 年,我们改用扁平化三元表达式,当时看似明智之举,却反响不佳——要求回退的议题获得了超 500 次支持。

尽管最终回归了缩进式三元表达式,我们仍希望找到更优方案。

过去几年间,我们探索了众多可能方案,力求在常见场景保持缩进式的可读性,同时适应更复杂的应用场景。

严苛标准

理想方案需满足以下标准:

  1. 任何情况下都能清晰辨识「if条件」、「then结果」和「else结果」的对应关系

  2. 代码排版应自然过渡:从单个三元式 → 双链式 → 长链简单案例 → 含嵌套条件的复杂结构(多数方案未通过此测试)

  3. JSX、TypeScript条件表达式(无法用if实现)和常规JS的语法应保持视觉一致性

  4. 能适应任意长度的嵌套链(例如含数十个分支的TypeScript条件类型)

缩进式方案明显未达标(4),在(1)上也存疑,甚至(3)——我们虽常将JSX三元式处理为扁平可读格式,但该格式在JSX之外显得生硬

社区中有许多人曾对“case风格”表示期待,这种风格借鉴了Rust或OCaml等语言的match语法,但它未能满足第(2)条标准以及其他目标

出人意料的解决方案

好消息是我们找到了满足所有标准的格式化算法;坏消息是这种算法非常新颖,对大多数开发者来说还很陌生。

在Beta测试阶段,我们发现开发者首次接触时普遍持怀疑态度:

"我不认为新版在这里更容易阅读"

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

"新三元表达式格式太棒了!这种排版逻辑清晰,我也很快就适应了。\n我同意,习惯这种格式只需要很短时间"

另一位开发者这样评价:

启用新规则的第一小时感觉有些奇怪。但到第二小时,我已经多次用它解决了原本需要改用丑陋if语句重构的问题。我不想再回去了。

我曾厌恶嵌套三元表达式,但更讨厌将简洁的代码重构成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"

改写后的代码展示"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