TypeScript 7.0发布:Go重写后编译速度提升12倍!


速度就是最好的新功能。

TypeScript 7.0正式发布,这是一个用Go语言重写的原生版本,编译速度提升最高达12倍,编辑器响应速度从17秒缩短到1.3秒以内。这项升级意味着大型项目的开发等待时间将大幅减少,CI构建成本显著降低,开发者体验迎来质的飞跃。

原生重写带来了数量级的性能飞跃

TypeScript团队去年启动了一个大胆的计划,把整个代码库用Go语言重写。这不是简单的翻译,而是在保持原有逻辑结构的前提下,充分利用多核处理器和共享内存的优势。新的代码库不再受限于JavaScript运行时的单线程模型,而是可以同时处理多个文件的解析、类型检查和代码生成。

官方给出的测试数据相当惊人。在VS Code自己的代码库上,TypeScript 6需要125.7秒完成的完整构建,TypeScript 7只需要10.6秒,速度提升了将近12倍。Sentry项目从139.8秒降到了15.7秒,Bluesky从24.3秒降到了2.8秒。这些不是玩具项目,都是真实世界的大型代码库。

内存使用量也同步下降了。VS Code项目的内存占用从5.2GB降到了4.2GB,减少了18%。Bluesky项目从1.8GB降到了1.3GB,减少了26%。更快的同时还更省内存,这在软件优化里算是双赢的局面。

编辑器里的等待时间终于可以消失了

大多数人使用TypeScript不是直接在命令行跑编译,而是在编辑器里写代码时的实时反馈。TypeScript的语言服务器负责提供自动补全、错误提示、查找引用、重命名这些功能。以前打开一个大型项目,要等十几秒才能看到第一个错误提示。

微软团队举了个例子,在VS Code代码库里打开一个文件,从打开编辑器到看到第一个错误提示,TypeScript 6需要17.5秒。而TypeScript 7只需要1.3秒以内,提升了超过13倍。这种差异带来的体验变化是质的区别,17秒足够让人走神去刷一下手机,而1.3秒就是眨个眼的功夫。

Slack的工程师反馈说,他们之前因为语言服务器加载太慢,几乎不在本地做类型检查,都靠CI跑。TypeScript 7能在几秒内加载同样的代码库,让本地类型检查重新变得可行。他们还提到合并队列的时间减少了40%,CI里的类型检查从7.5分钟降到了1.25分钟。

多线程并行处理让CPU核心不再闲置

TypeScript 7引入了几个新的命令行参数来控制并行行为。--checkers参数控制同时运行多少个类型检查器工作线程,默认是4个。--builders参数控制在项目引用构建模式下并行构建多少个项目。还有一个--singleThreaded参数可以强制单线程运行,用于调试或资源受限的环境。

在同样的机器上把类型检查器从4个增加到8个,VS Code的构建时间从10.6秒进一步降到了7.51秒,速度提升从11.9倍变成了16.7倍。Sentry从15.7秒降到了12.08秒,Bluesky从2.8秒降到了2.01秒。不过不是所有项目都适合开更多线程,内存占用会相应增加,需要根据机器配置和项目规模找到平衡点。

团队解释说类型检查的并行化有个特殊挑战,大多数文件依赖相同的全局类型信息和依赖项的类型。如果完全独立运行检查器,会造成重复计算和内存浪费。他们采取的策略是创建固定数量的工作线程,每个线程有自己的世界视图,对输入文件做相同的划分,确保输出结果一致。

和TypeScript 6.0和平共处的方法

TypeScript 7.0目前没有提供API接口,这意味着依赖编程方式调用TypeScript的工具暂时没法升级。比如typescript-eslint、Webpack的ts-loader、还有各种构建工具的插件,目前都只能继续使用TypeScript 6.0。

为了让大家能平稳过渡,官方发布了一个兼容包@typescript/typescript6。这个包提供了名为tsc6的可执行文件,并重新导出了TypeScript 6.0的API。你可以同时安装TypeScript 7.0和这个兼容包,两者互不冲突。用tsc命令调用新版,用tsc6调用旧版。

对需要从typescript包直接导入的工具,推荐使用npm的别名功能来解决。在package.json里把typescript指向@typescript/typescript6,同时用另一个别名安装TypeScript 7.0。这样npx tsc默认还是用7.0,而依赖typescript包的工具照常使用6.0的API。

监听模式改用Parcel的文件监听器

TypeScript 7完全重写了--watch模式的实现。以前的文件监听逻辑在跨平台支持上有不少麻烦,Go语言标准库没有内置的文件监听API,第三方库要么不稳定,要么性能有问题,要么跨平台支持不完善。团队尝试过基于轮询的解决方案,在大项目里CPU开销太大。

他们最后选择了Parcel打包器的文件监听器作为基础。这个监听器用C++写的,VS Code多年以来一直在用它,稳定性和性能都经过了验证。团队把C++版本移植到了Go,只用了少量的汇编做桥接,避免引入额外的工具链依赖。

移植后的效果很不错,跨平台的文件监听更加稳定高效,CPU和内存占用都有明显改善。早期使用TypeScript 7预览版的用户反馈相当正面。团队还特别感谢了Parcel的作者Devon Govett,说他的工作让VS Code和TypeScript两个项目都受益巨大。

TypeScript 7.0继承了6.0的默认配置变更

TypeScript 6.0引入了一系列默认配置的变更,7.0直接继承了这些变更,并且把6.0中标记为弃用的配置项升级成了硬错误。如果你的项目已经在TypeScript 6.0下干净编译,那直接升级到7.0不会有类型层面的变化。

重要的默认值变更包括strict现在默认为truemodule默认为esnexttarget默认是当前稳定版ECMAScript的前一个版本,noUncheckedSideEffectImports默认为truetypes现在默认为空数组,以前是自动包含所有@types包,现在需要显式列出。rootDir现在默认是./,以前是自动推断。

target: es5不再支持,moduleResolution: nodenode10不再支持,推荐使用nodenextbundlerbaseUrl不再支持,paths配置现在相对于项目根目录。esModuleInteropallowSyntheticDefaultImports不能再设为false

types的变化可能会让不少人意外,以前只要装了@types/node就能直接用,现在必须在tsconfig.json里显式配置。rootDir的变化会影响目录结构,如果你的tsconfig.json在项目根目录,代码在src子目录里,现在需要明确指定rootDir: "./src"

模板字面量类型现在按Unicode码点处理

这是一个细微但重要的类型系统改进。以前在模板字面量类型里做模式匹配时,TypeScript遵循JavaScript的UTF-16索引行为。对于包含emoji的字符串,会被拆成两个代理对来处理。


对于大部分日常使用来说这是个正向的改进,只有那些专门利用UTF-16索引行为的类型工具代码会受到影响。如果你写过计算字符串长度的类型工具,可能需要检查一下是否依赖于旧的索引方式。

JavaScript文件的支持方式被重新梳理

TypeScript原本对JavaScript文件的支持依赖于JSDoc注释和识别特定的代码模式。很多行为是基于流行的编码习惯推测的,有时候还兼容了Closure Compiler和JSDoc文档生成工具的理解方式。这导致对JS文件的分析和对TS文件的分析有不少不一致的地方。

7.0版本重写了JS支持,让它和TS文件的处理方式更加一致。现在不能在类型位置上直接使用值,需要写typeof someValue@enum不再特殊识别,需要用@typedef结合keyof来实现同样的效果。单独的?不能用作类型,用any代替。@class不会让函数变成构造函数,用真正的class声明。

Closure风格的函数类型语法不再支持,比如function(string): void这种写法,要用TypeScript风格的(s: string) => void。一些常见的JS模式,比如给this起别名、直接替换函数的prototype对象,也不再特殊处理了。

编辑器生态的适配情况和下一步计划

VS Code用户可以通过专门的扩展来使用TypeScript 7,安装后自动成为默认的语言服务器。Visual Studio的最新版本会根据工作区自动启用TypeScript 7。其他支持LSP的编辑器理论上都能用,新版基于语言服务器协议构建,支持多线程处理并发请求。

但Vue、MDX、Astro、Svelte这些框架的开发者暂时还不能在编辑器里用TypeScript 7。原因很简单,这些工具把TypeScript嵌入到自己的编译器和语言服务中,需要调用TypeScript的API。7.0目前没有稳定的API,所以这些工具只能继续依赖6.0。

团队承诺会在7.1版本提供新的API,并且会和这些项目的维护者合作,尽快让它们支持TypeScript 7。在过渡期间,Angular项目可以这样用:命令行里用7.0跑tsc获得快速的全项目错误检测,编辑器里用6.0获得模板内的类型支持。Vue等项目的用户目前只能继续用6.0,在VS Code里可以执行禁用TypeScript 7语言服务器的命令切回6.0。

TypeScript 7.0的测试工作做得相当扎实。除了自带的数万个测试用例,团队还构建了针对GitHub上大量TypeScript和JavaScript项目的自动化测试系统。他们在内部和外部找了多家大公司做实际代码库的测试,包括微软内部的Loop、Office、PowerBI、Teams、Xbox团队,以及外部的Bloomberg、Canva、Figma、Google等。根据收集到的数据,新的语言服务器比6.0减少了80%以上的命令失败率,服务器崩溃率降低了60%以上。

下一步团队会重新投入新功能开发,7.1版本预计在3到4个月后发布,主要目标就是提供新的API接口,让整个工具生态都能迁移到原生版本上来。

这次升级的核心信息就一句话:TypeScript变快了,快了很多很多。过去一年团队把整个编译器用Go重写了一遍,带来的性能提升让大型项目的开发体验有了本质改变。

速度一旦提上来了,就再也回不去了。