
微软已经着手将 TypeScript 编译器和工具集移植至 Go,旨在实现各类代码库的 10 倍编译速度提升。大部分开发者都觉得这是个好消息。不过,也有一些人感到不解,他们想知道,为什么微软选择了 Go 语言,而不是 Rust 语言来做这件事。
昨天,TypeScript 之父 Anders Hejlsberg 在一篇博文中宣布,微软已启动一项计划,将 TypeScript 编译器和工具移植至代号为“Corsa”的原生 Golang 实现。通过这次原生实现,微软承诺性能将提升 10 倍,同时增强开发者体验,并引入全新的 AI 驱动功能。
Hejlsberg 表示,这项工作还解决了大型代码库面临的扩展性挑战。TypeScript 用户目前在处理大型代码库时,往往面对加载时间过长、类型检查缓慢以及内存限制等问题,因此开发者被迫在合理的编辑器启动时间和获取源代码完整视图之间做出选择。
现在,通过将 TypeScript 编译器移植到 Go 语言,微软不仅提升了性能,还有效应对了扩展性挑战。
向 Go 迁移,获得 10 倍提升
关键性能提升包括:构建时间缩短约 10 倍,项目加载速度提升 8 倍,内存占用减少至当前实现的大约一半(预计未来还将进一步优化)。此外,语言服务方面也有显著改进,补全、快速信息(quick info)、跳转到定义以及查找所有引用的速度均大幅提升。
“原生实现将显著加快编辑器启动速度,使大多数构建时间缩短 10 倍,并大幅降低内存占用。”Hejlsberg 写道。
新的原生版本在多个热门代码库上展现出了卓越的性能指标:
VS Code (1,505,000 LOC): 77.8s → 7.5s(提升 10.4 倍)
Playwright (356,000 LOC): 11.1s → 1.1s(提升 10.1 倍)
TypeORM (270,000 LOC): 17.5s → 1.3s(提升 13.5 倍)
date-fns (104,000 LOC): 6.5s → 0.7s(提升 9.5 倍)
tRPC (18,000 LOC): 5.5s → 0.6s(提升 9.1 倍)
rxjs (2,100 LOC): 1.1s → 0.1s(提升 11.0 倍)
性能提升 10 倍,这不仅仅是数字上的变化,它意味着 TypeScript 和 JavaScript 的开发体验迎来了巨大飞跃。
以编辑器为例,大多数开发者的工作时间几乎都在编辑器中度过,因此编辑器的性能至关重要。理想情况下,它应能快速加载大型项目,并在各种操作中保持流畅响应。而编辑器的核心性能很大程度上取决于底层语言服务的速度。借助原生实现,TypeScript 的编辑体验达到了前所未有的流畅度。
为了更具体地说明这一点,以 Visual Studio Code 代码库为例,目前在高配置计算机上将完整项目加载至编辑器中的用时约为 9.6 秒。而使用原生语言服务之后,加载时间缩短至 1.2 秒左右,提升约 8 倍。
在解释为何要更换语言时,Hejlsberg 指出,JavaScript(TypeScript 所基于的语言)主要用于 UI 和浏览器场景,而并不适用于编译器或系统级工具等计算密集型工作负载。他补充道,微软可能已经接近 JavaScript 性能优化的极限,“我们能从 JavaScript 中榨取的性能提升空间已经所剩无几。”
在开发策略方面, Hejlsberg 表示,他们的团队明确希望对 TypeScript 编译器进行移植(port),而不是完全重写(rewrite)成 Go。
在 TypeScript 项目的常见问题解答(FAQ)中,TypeScript 团队的开发负责人 Ryan Cavanaugh 进一步解释说,在更换编程语言时,通常有两种策略可选。一是重写(rewrite), 从零开始实现一个新的系统,目标是解决与原系统相同的问题,但不考虑原有代码库的实现方式。二是移植(port),以现有代码库为基础,将其转换为新的语言,同时尽可能保持原有架构和逻辑不变。而移植的执行速度更快,但前提是新语言在架构上与原语言至少有一定的兼容性。
Hejlsberg 表示,微软曾尝试用 C#、C++、Rust 等常见候选语言进行原型开发,但最终发现 Go 最适合他们的特定工作负载。
Arcjet CEO David Mytton 在接受媒体采访时表示:
“非常有趣!JS 开发者早已习惯了慢速的工具,因此一个能加快编辑器启动时间的高速编译器无疑是个好消息。迁移到原生编译器是合理的选择,尽管 Go 作为这一类项目的实现语言有些不太常见。看到这个公告时,我本以为他们会像其他 JS 工具重写项目那样选择 Rust,比如 Rolldown、Turbo(从 Go 迁移到 Rust)、Deno……我很好奇他们做出这一决策的原因。” (编者注:此外还有个 SWC,一个用 Rust 编写的 TypeScript/JavaScript 编译器,被 Next.js、Parcel、Deno、Vite 等工具采用。)
对于这个问题,Cavanaugh 在 FAQ 中回应称,考虑到多个特定因素,Go 仍然是最优选择。
“最关键的一点是,我们需要尽可能保持新代码库的兼容性,无论是在语义层面还是代码结构上。” 他写道,“我们预计未来相当长一段时间内会同时维护两个代码库,因此能够保持结构相似的语言对于代码迁移和维护极为有利,因为这样我们可以更轻松地在两个代码库之间同步变更……”
基于 Go 的 TypeScript 实现现已在 GitHub(https://github.com/microsoft/typescript-go)开源,并已能够加载多个主流 TypeScript 项目,包括 TypeScript 编译器自身。
Rust 粉丝震惊:为何没有选择 Rust?!
有网友好奇,微软 TypeScript 团队在最终选择 Go 语言之前,到底尝试了 Rust 多久?毕竟 Rust 以性能和安全性著称。有人调侃说:“我听说他们几乎撑过了午饭时间才换的。” 这句话可能暗示 TypeScript 团队并没有对 Rust 进行深入的尝试。

事实上,不少人对此决定感到不解,他们想知道,为何微软最终没选 Rust。这种疑惑和不解的情绪,在社交媒体上尤为明显。正如一位 X 网友所言:“比 TypeScript 实现 10 倍提速更令人震惊的是,他们竟然没有选择 Rust。”

另一位用户更是直言,“转眼间,Java 与 C# 谁更好的战火就蔓延到了 Rust 和 Go 这边。感谢 TypeScript 煽动了这场纷争。”

显然,TypeScript 团队的选择在开发者社区中引发了关于编程语言选择的激烈讨论。更有甚者,有用户以幽默的方式表达了对 Rust 拥趸的看法,“为什么 Rust 狂热者在 TypeScript 选择 Go 重写编译器时哭泣?因为他们无法接受 Go 在不需要生命周期保证的情况下也能抢走风头!”

随着不满情绪的出现,TypeScript 首席开发者 Ryan Cavanaugh 出面做出澄清,承认他们已经预料到开发者社区就会此展开争论。
他提到,虽然 Rust 也是个不错的选择,但“决定性因素”在于可移植性,即如何确保新代码库在算法上与当前代码库保持一致。
他还透露,TypeScript 团队探索了多种方法来表示代码,检验用 Rust 重写代码是否可行。但其在性能和开发体验等方面带来了“不可接受的”问题。某些方案需要单独实现垃圾收集器(GC),这会增加额外的复杂性。
与之形成鲜明对比的是,Go 语言具备内存自动回收机制,即所谓“垃圾收集”。Cavanaugh 坦言,“虽然二者中的某些机制相当接近,但 Rust 往往需要使用大量不安全代码,而且 Rust 似乎缺少充足的原语组合来实现有益于开发者体验的 JavaScript 代码移植目标。”
他解释称,团队最终面临着两个选项。要么使用 Rust 从头开始重写,而这可能需要耗费“数年时间”,并最终产生一个“没人愿意用”的 TypeScript 版本;要么在一年之内用 Go 构建一个可用的移植版本,在语义方面“高度”兼容,同时提供具有竞争力的性能表现。
Cavanaugh 同时强调,Go 与 Rust 一样,都具备出色的代码生成、数据表示能力和“强大的”并发原语。就设计目标而言,Rust 的表现也算相当出色,但“将特定 JavaScript 代码库直接移植为 Rust”则并不贴合这款编程语言的设计特性。
他承认,Go 其实也有类似的问题,但结合此前 TypeScript 的代码编写方式,Go 出人意料地非常适合这项移植任务。
他在 GitHub 上的一篇帖子中补充道,“我们还有大量图形处理任务,特别是涉及多态节点的向上与向下遍历树。Go 在处理这些工作时仍可提供良好的开发者体验,特别是在处理 JavaScript 版本代码方面尤其突出。”

在接受采访时,TypeScript 首席架构师 Anders Hejlsberg 也基本重申了 Cavanaugh 的观点。
他提到,该项目的核心意义所在,就是要按原本移植现有代码库。原始代码库是根据某些假设条件设计而成——其中最重要的一点,就是必须存在自动垃圾收集机制。
Hejlsberg 表示,“可以说这限制了我们的选择范围,也让 Rust 基本退出了决赛圈”,这里指的当然是 Rust 缺少自动内存管理。

原始 TypeScript 与移植后的 Go 代码仍高度相似。
正如 Hejlsberg 的解释,Rust 面对的另一个挑战,是它对循环数据结构做出了严格限制,而 TypeScript 编译器高度依赖循环数据结构。该系统包含具有父子引用的抽象语法树(AST)、相互引用的符号与声明,以及自然形成循环的递归类型。
“这些问题的存在,使得原生代码的迁移工作变得极其困难。”Hejlsberg 还解释道,考虑到这种种需求,Go 最终脱颖而出、成为最合适的选项。
值得注意的是,TypeScript 建立在 JavaScript 之上。“如果大家经常使用 JavaScript,就知道向 Go 迁移比向 Rust 迁移要简单得多。”
Hejlsberg 还表示,这样的 Go 转换对于系统的影响也非常温和,毕竟其并不是那种强调繁文缛节的“特别复杂”的语言,“而 Rust 则恰恰相反”。
未来规划
微软预计将在 2025 年年中推出具备命令行类型检查功能的原生 tsc 预览版(tsc 即 TypeScript 编译器)。到 2025 年底,项目构建和语言服务的完整实现版本有望发布。目前最新的 TypeScript 版本是 TypeScript 5.8,TypeScript 5.9 也即将发布。JS 版本的代码库仍将持续开发,进入 6.x 版本系列。同时,TypeScript 6.0 将引入部分废弃特性和破坏性变更,以便与即将推出的原生代码库保持一致,Hejlsberg 透露。
“当原生代码库与当前 TypeScript 版本达到足够的功能对等时,我们将正式发布 TypeScript 7.0。”
此外,Hejlsberg 进一步解释道: “为了便于区分,我们会直接将它们称为 TypeScript 6(JS 版本)和 TypeScript 7(原生版本),这一命名方式将在可预见的未来保持不变。
在内部讨论或代码注释中,你可能还会看到 ‘Strada’(TypeScript 的原始代号)和 ‘Corsa’(此次原生迁移的代号)这两个名称。”
与此同时,除了速度提升,原生版本还带来了额外的优势,包括:即时、全面的错误列表,覆盖整个项目;更高级的重构能力;更深入的代码分析,此前由于计算成本过高而难以实现;同时为下一代 AI 赋能开发工具奠定基础。微软还计划迁移至 Language Server Protocol(LSP),以更好地对齐其他编程语言的开发体验。
“TypeScript 的核心价值主张是提供卓越的开发体验。” Hejlsberg 写道,“随着代码库规模的增长,TypeScript 的价值也在提升。但在许多情况下,它仍难以扩展到超大规模代码库。”
参考链接:
https://devblogs.microsoft.com/typescript/typescript-native-port/
https://github.com/microsoft/typescript-go/discussions/411
https://thenewstack.io/go-power-microsofts-bold-bet-on-faster-typescript-tools/
评论