news 2026/9/18 15:07:04

Prettier 3.10:保留解构模式后的类型注释位置(TypeScript 格式化变更 19905)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Prettier 3.10:保留解构模式后的类型注释位置(TypeScript 格式化变更 19905)

Prettier 3.10:保留解构模式后的类型注释位置(TypeScript 格式化变更 #19905)

【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier

本篇技术指南基于 Prettier 仓库中未发布的变更条目 changelog_unreleased/typescript/19905.md,解析 Prettier 对 TypeScript 类型断言语句的一个格式修复:当解构赋值/参数后面跟随: Type类型标注时,位于模式右花括号与冒号之间的行内注释(如/* comment */)不再被移动进解构模式内部,而是保留在其原始位置。读完本文,你能理解该变更的前后行为差异、注释在 Prettier 格式化管线中"附着—打印"的底层机制,以及如何在仓库中复现和验证这类格式化行为。

一、变更内容:注释留在模式之后

变更条目的原文示例如下(来自 19905.md,由 @lazerg 贡献):

// Input const { foo } /* comment */ : Foo = bar; // Prettier stable const { foo /* comment */ }: Foo = bar; // Prettier main const { foo } /* comment */ : Foo = bar;

三段输出的含义:

  • Input:多行解构对象模式const { foo },紧接着一个行内注释/* comment */,再换行后是: Foo类型标注和默认值= bar
  • Prettier stable(旧版稳定行为):压缩为单行时,注释被移动到了模式内部,成为}前面的内容——const { foo /* comment */ }。这改变了注释与源码中代码实体的视觉绑定关系:原本它标注的是"模式结束之后的类型标注",现在却看起来像是模式内最后一个属性foo的尾随注释。
  • Prettier main(本变更后的行为):注释保留在模式关闭括号之外、类型冒号之前——const { foo } /* comment */ : Foo = bar

这个变更属于 Prettier 变更日志流程中typescript/目录下的标准条目。按照 changelog_unreleased/TEMPLATE.md 的约定,每个 PR 对应一个XXXX.md文件,内容为"输入 + 旧版输出 + 新版输出"的对比示例;TypeScript 特定语法(如类型标注、as断言)归属typescript/目录。

二、涉及的代码:类型标注语句的打印方式

const { foo }: Foo = bar;这类语句在类型标注的打印路径中,与as/satisfies断言共享同一套"表达式 + 运算符 + 类型"的三段式输出逻辑。在 src/language-js/print/typescript.js 中:

case "TSAsExpression": case "TSSatisfiesExpression": return printBinaryCastExpression(path, options, print);

对应的打印实现位于 src/language-js/print/binary-cast-expression.js:

function printBinaryCastExpression(path, options, print) { const { parent, node, key } = path; const isFlowAsConstExpression = node.type === "AsConstExpression"; const typeAnnotationDoc = isFlowAsConstExpression ? "const" : print("typeAnnotation"); const parts = [ print("expression"), // 左操作数:表达式(此处为解构模式) " ", isSatisfiesExpression(node) ? "satisfies" : "as", ]; if ( // Union type already indented !isUnionType(node.typeAnnotation) && hasLeadingOwnLineComment(options.originalText, node.typeAnnotation) ) { parts.push(indent([hardline, typeAnnotationDoc])); } else { parts.push(" ", typeAnnotationDoc); } // ...(callee/object 场景的缩进分支) }

从源码结构看,这类语句的输出是"先打印表达式子树,再打印类型标注子树"。注释并不参与表达式子树内部的排版——它们在解析后通过独立的注释附着阶段被分配到各个 AST 节点上,最终由节点的打印函数决定其相对位置。hasLeadingOwnLineComment分支也体现了这一点:如果类型标注自带独占行的前导注释,会触发换行缩进,而不是把注释塞进左侧表达式。这正是修复"注释被吸入模式内部"这类问题的落点——注释最终锚定在"模式结束符之后",而不是}之前。

三、注释附着:为什么修复点不在打印函数本身

Prettier 的注释处理是一个独立于语言打印的通用阶段。核心判断逻辑在 src/language-js/comments/can-attach-comment.js,它根据节点及其祖先链决定某条注释是否允许附着到某个 AST 节点上,例如其中针对TSAsExpression场景的专门判断(can-attach-comment.js#L87-L107):

// `foo as const` // ^^^^^^^^^^^^ `TSAsExpression` // ^^^^^ `TSTypeReference` (`TSAsExpression.typeAnnotation`) // ^^^^^ `Identifier` (`TSTypeReference.typeName`) const isTsAsConstTypeReference = (node, [parent]) => // @ts-expect-error -- Safe parent?.typeAnnotation === node && isTsAsConstExpression(parent);

可以推断,#19905 的修复正是作用于这一附着判定/输出位置:旧逻辑把紧跟模式}的注释视为模式内部最后一个元素的尾随注释(因此被排进花括号内);修复后,由于该注释实际位于类型标注之前,它被保留为模式之后的独立片段,即{ foo } /* comment */ : Foo

同一套机制在satisfies场景下已有对应的行为测试。仓库中的测试输入 tests/format/typescript/satisfies-operators/comments.ts 包含:

const t2 = {} /* comment */ satisfies {};

其快照(satisfies-operators 快照)确认注释稳定地保留在{}satisfies之间。这说明"注释留在断言表达式与类型之间"是 Prettier 已确立的排版原则,#19905 把这一原则扩展到了对象/数组解构模式带: Type标注的场景。

四、关联测试:类型标注注释的一致性验证

仓库中有一组专门覆盖"模式后类型标注与注释"行为的格式化测试:tests/format/typescript/comments/consistent-with-flow/15707.ts。该文件以typescriptflow双解析器运行(见 format.test.js):

runFormatTest(import.meta, ["typescript", "flow"]);

其输入覆盖了对象模式、数组模式、函数参数等多种形态:

const { foo11, // bar // baz }: Foo = expr; const [ foo31, // bar // baz ]: Foo = expr; function method({ foo, // bar = "bar", // bazz = "bazz", }: Foo) {} const { // foo }: Foo = expr;

对应快照 15707.ts 格式化快照 记录了这些用例在两种解析器下的精确输出。结合 #19905,可以推断这条测试线覆盖的就是"注释不得在模式与类型标注之间被错误迁移"这一类问题——15707 处理的是模式内部注释,19905 处理的是模式之后注释,二者共同构成该语法区域注释行为的回归防护。

五、如何验证这一行为

Prettier 仓库的格式化行为验证基于 Jest 快照测试:

  1. 测试入口使用runFormatTest(配置见 tests/format/format-test 目录),它会读取测试目录下的输入文件、按指定解析器格式化,并与__snapshots__下的快照逐字比对。
  2. 以本文主题为例,tests/format/typescript/comments/consistent-with-flow/目录下的每个输入文件都有对应的format.test.js驱动,双解析器(typescriptflow)的输出都会写入 format.test.js.snap。
  3. 若想观察变更条目的完整格式约定(标题、PR 号、作者、示例代码),可参考 changelog_unreleased/TEMPLATE.md:示例需给出// Input// Prettier stable(旧行为)、// Prettier main(新行为)三段,并用<!-- prettier-ignore -->保持原文排版。

六、影响范围与适用前提

  • 语言范围:该变更针对 TypeScript 特定语法(对象/数组解构模式 +: Type类型标注 + 默认值的变量声明),归属变更日志的typescript/目录;从源码结构看,类似的"表达式 + 类型"断言输出(as/satisfies)走 binary-cast-expression.js 同一机制,行为已有一致性。
  • 适用前提:变更条目位于changelog_unreleased/目录,说明该行为尚未进入已发布的稳定版本线;"Prettier stable" 输出代表旧行为,"Prettier main" 输出代表本变更落地后的行为。
  • 对用户的实际影响:如果你的代码依赖"模式后注释"的精确位置(例如用/* TODO */标注类型标注前的待办),升级后注释将保持在冒号之前的原始位置,而不会被移入花括号内部;格式化结果更符合源码的原始意图。

参考路径

  • 变更条目:changelog_unreleased/typescript/19905.md
  • 变更日志模板:changelog_unreleased/TEMPLATE.md
  • 断言表达式打印:src/language-js/print/binary-cast-expression.js
  • TS 节点分发:src/language-js/print/typescript.js
  • 注释附着判定:src/language-js/comments/can-attach-comment.js
  • 关联测试:tests/format/typescript/comments/consistent-with-flow/15707.ts、tests/format/typescript/satisfies-operators/comments.ts

【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 15:04:49

MCU嵌入式开发真实能力栈:从寄存器直驱到工业级可靠性

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 15:03:12

商业化谈判中的定制化防线:如何用标准组件满足 80% 定制需求

商业化谈判中的定制化防线&#xff1a;如何用标准组件满足 80% 定制需求在面向中大型企业客户的商业化销售谈判中&#xff0c;创始人与售前架构师最常听到的客户要求莫过于&#xff1a;“你们的系统功能很好&#xff0c;但我们公司的业务极其特殊。我们需要你们单独为我们定制 …

作者头像 李华
网站建设 2026/9/18 15:02:34

SigmaStudio音频DSP模块计算暗坑:定点运算与格式转换实战解析

1. 音频DSP开发里的“暗知识”&#xff1a;为什么SigmaStudio的模块计算总跟手册对不上搞音频DSP的人&#xff0c;绕不开ADI的SigmaStudio这套图形化开发环境。尤其是用ADAU系列芯片做产品——车载音响、Soundbar、会议全向麦、专业调音台——SigmaStudio几乎是默认选项。拖拖拽…

作者头像 李华