用 LLM 将 TypeScript 编译器、类型检查器和 LSP 移植到 Rust
摘要
一个项目展示了完全借助 LLM 将微软的 TypeScript 编译器、类型检查器和 LSP 移植到 Rust 的过程——Anthropic 的 Opus 5.5 以约 2.4 万美元的 API 成本从头重写了整个代码库,实现了与真实项目完全兼容,可作为早期发布的 `tsc-rs` 直接替代品使用。
查看缓存全文
缓存时间: 2026/10/08 12:44
pingdotgg/ts-rust
来源:https://github.com/pingdotgg/ts-rust
ts-rust(又名 tsc-rs)
我想试试大语言模型能不能把 TypeScript 编译器、类型检查器和 LSP 移植到 Rust。结果是它们能做到。整个过程花费了超过 42 万美元的 token 费用,但你可能只需大约 2 万美元就能做到(见下文)。
动机
- 测试模型的能力
- 制作一个更快的 TypeScript 类型检查器
- 做一个能在 WASM 中高性能运行的 ts checker
- 玩梗
警告
这是一个早期版本。 在我们测试过的所有真实项目中都达到了 100% 的兼容性。对绝大多数应用来说,它应该可以直接替换。参见已知问题。
另外值得一提:这段代码我一行都没读过。
安装
请注意,我不确定这东西是否真的能用。
npm install -D tsc-rs
npx tsc-rs -p tsconfig.json
这个过程是怎么回事?
我用了大量 OpenAI 模型来尝试完成这个移植。总共我在 API 定价的 token 上花费了超过 40 万美元,使用的模型是 GPT-5.6 Sol 和 GPT 6 Astra。它们在多个月的 /goal 循环中写了超过 130 万行 Rust 代码,但兼容性始终没有突破 84% 左右。
当我注意到我的 Claude Code 额度消耗得如此之少时,我觉得把 Opus 5.5 扔到这个任务上会很有趣。它在 10 小时内就完成了一个可工作的 v0。我还以为它在继续使用 Codex 模型写的代码。我错了。
Opus 5.5 是从零开始的。它在十分之一的时间内比 Astra 走得更远。
我让它继续跑,它确实一直在推进。总 token 花费是两周内约 24,047 美元的 API 开销。我使用的是我的 Claude 账户,折算下来相当于我 200 美元套餐每周额度的 925% 到 983%。
确实很贵,但考虑到 typescript-go 上投入了多少工作量,也不算太离谱。
“水线以下”
此线以下的内容全部由我的 LLM 撰写,非我本人所写。
这到底是什么?
ts-rust 是对 Microsoft 原生 TypeScript 编译器的直接移植,该编译器用 Go 编写(microsoft/TypeScript(https://github.com/microsoft/TypeScript),前身为 typescript-go(https://github.com/microsoft/typescript-go))。它保留了 Go 版的算法和行为,并拥有相同的命令行(tsc)、语言服务器和 API。
安装
npm install -D tsc-rs
npx tsc-rs -p tsconfig.json
tsc-rs 接受与 tsc 相同的选项。npm 包名为 tsc-rs,以避免与 typescript 包冲突。每个版本发布(https://github.com/pingdotgg/ts-rust/releases)也包含按平台分发的独立压缩包:tsc 二进制文件及其旁边的库文件。
支持平台:Linux x64(静态链接,适用于任何发行版)和 macOS arm64。Windows 和 Linux arm64 尚不可用。
要在 VS Code 中使用,请参阅 npm 包 README。
Effect 诊断
tsc-rs 内置了 Effect(https://effect.website)语言服务诊断功能(编码为 377xxx),因此 Effect 项目不需要第二个编译器。它们与 TypeScript 诊断来自同一个检查流程,语言服务器同样会显示这些诊断。
它们仅在 tsconfig 中配置了该插件时运行,与 @effect/language-service 的行为一致:
{
"compilerOptions": {
"plugins": [{ "name": "@effect/language-service" }]
}
}
这些规则、选项和 @effect-diagnostics 注释移植自 Effect-TS/tsgo(https://github.com/Effect-TS/tsgo)0.46.1。语言服务的编辑器功能(快速修复、重构、悬停、补全)尚未移植。
状态
本次移植锁定在上游的某一个修订版本:microsoft/TypeScript 673a5f17d713(https://github.com/microsoft/TypeScript/commit/673a5f17d713bdc8c7185f18a9c11e3c4ac5d781)(2026-09-29,TypeScript 7.1.0-dev;UPSTREAM.md),并与该修订版本的 Go 版本进行比较。要进行对比,请使用 [email protected],而非 7.0.x 或 @typescript/native-preview。
本构建所展示的差异也属于上游行为,当移植版本更新到更新的锁定版本时差异就会消失。
- 结果相同。 TanStack Query core 和 Hono 的检查诊断结果与 Go 版完全一致。全部 181,711 个移植的 Go 测试全部通过。语言服务器和 API 在基准测试集上与 Go 版的回答一致。
- 更快。 在 60 个开源项目上,类型检查耗时约为 Go 版的一半(几何平均值)。预览包在 CI 中构建时未启用 PGO 和 BOLT,因此比测量时的构建版本更慢。
- 真实项目。 在 120 个开源仓库上,命令行输出仅在下述问题以及 Go 版自身输出在多次运行间变化的地方存在差异。
基准测试:T3 Code
对 T3 Code(https://github.com/pingdotgg/t3code)进行完整类型检查,与 tsc 6、tsc 7 以及 Bun 中新的 bun check 进行比较。
T3 Code 使用了 Effect,因此分为两种情况:不含 Effect 诊断和含 Effect 诊断。每个时间都是 T3 Code 五个项目的总和。时间越短越好。
不含 Effect 诊断
| 检查器 | 耗时 | vs tsc 6 | vs tsc 7 |
|---|---|---|---|
bun check | 4.07s | 15.4× | 3.95× 更快 |
tsc-rs | 7.25s | 8.6× | 2.22× 更快 |
tsc 7 | 16.10s | 3.9× | 基准 |
tsc 6 | 62.63s | 基准 | 3.89× 更慢 |
含 Effect 诊断
| 检查器 | 耗时 | vs tsc 6 | vs tsc 7 + Effect |
|---|---|---|---|
tsc-rs(Effect 内置) | 11.13s | 12.5× | 1.89× 更快 |
tsc 7 + @effect/tsgo | 21.07s | 6.6× | 基准 |
bun check,再运行 effect-tsgo diagnostics | 37.60s | 3.7× | 1.78× 更慢 |
tsc 6 + @effect/language-service | 138.63s | 基准 | 6.58× 更慢 |
当你不需要 Effect 诊断时,bun check 是最快的。它不包含 Effect 诊断,因此 Effect 项目需要运行第二遍。tsc-rs 在一次检查中就获得了这些诊断。
错误。 tsc-rs、tsc 7 + @effect/tsgo 以及 effect-tsgo diagnostics 流程报告了相同的 221 个 Effect 诊断。tsc 6 使用 JavaScript 版 Effect 插件(@effect/language-service 0.87.4),其规则集有所不同:在 apps/server 上报告了 287 个,而其他工具报告 177 个。
tsc-rs 和 tsc 6 多报告了一个错误:apps/server/scripts/record-pi-rpc-replay-fixture.ts 中的 TS2322。TypeScript 7.1.0-dev 也会报告该错误,pingdotgg/t3code#16704(https://github.com/pingdotgg/t3code/pull/16704)修复了它。
测量方式:与下方真实项目基准相同的机器和方法,额外添加了 --composite false(apps/web 是复合项目)。T3 Code 使用 cd41c4ad(https://github.com/pingdotgg/t3code/tree/cd41c4ada0c70cc2eec95ecd7266f3dab010c58c),包含 apps/server、apps/web、apps/mobile、packages/client-runtime 和 packages/shared。
不含 Effect 时,配置中不包含 Effect 插件。含 Effect 时,tsc 7 是来自 @effect/tsgo 0.46.1 的打了 Effect 补丁的 7.0.2 版本,tsc 6 是打了 @effect/language-service 补丁的 6.0.3 版本。
脚本位于 scripts/bench-apps/t3code.sh。T3 Code 中的 tsc-rs 开关是 pingdotgg/t3code#16704(https://github.com/pingdotgg/t3code/pull/16704)。
基准测试:真实项目应用
使用 tsc 6(JavaScript 编译器)、tsc 7(Go 编译器)、tsc-rs 和 bun check 对六个开源应用进行完整类型检查。
倍数表示相对于 tsc 6 的加速比。时间越短越好。
| 应用 | 检查行数 | tsc 6 | tsc 7 | tsc-rs | bun check |
|---|---|---|---|---|---|
| VS Code(https://github.com/microsoft/vscode/tree/3f07e1aba32acacb8b08ae91bfdc954b580ad1fd) | 3.75M | 54.56s | 6.84s (8.0×) | 4.20s (13.0×) | 1.62s (33.7×) |
| Sentry(https://github.com/getsentry/sentry/tree/8294650589dbd26f230c73f4ab26b62a68aede8f)(前端) | 2.11M | 58.76s | 7.90s (7.4×) | 4.46s (13.2×) | 3.14s (18.7×)* |
| Playwright(https://github.com/microsoft/playwright/tree/d469960fdfc461e2d5795a3fa48a58a52a91ecaf) | 585k | 4.48s | 0.66s (6.8×) | 0.34s (13.2×) | 0.18s (25.0×) |
| Excalidraw(https://github.com/excalidraw/excalidraw/tree/53973c3a423fbd75a4ce68107786b4fcb90e4968) | 449k | 5.32s | 0.80s (6.7×) | 0.70s (7.6×) | 0.18s (29.0×) |
| TypeORM(https://github.com/typeorm/typeorm/tree/c64a1f052fc39f6688b6b73b83d065d7147ba8bb) | 386k | 3.86s | 0.55s (7.0×) | 0.36s (10.7×) | 0.19s (20.0×) |
| tRPC(https://github.com/trpc/trpc/tree/d756e591a5e37ef20b8d75ecd4d736c195497289)(server 包) | 209k | 1.10s | 0.16s (6.8×) | 0.09s (12.0×) | 0.12s (9.1×)* |
| 几何平均 | 7.1× | 11.4× | 20.9× |
与 tsc 7 相比,tsc-rs 快 1.61 倍,bun check 快 2.95 倍(几何平均值)。bun check 在除 tRPC 外的每个应用上都是最快的。
* bun check 报告了其他检查器都没有报告的错误:Sentry 上 3 个,tRPC 上 2 个。在 tsc 7.0.2 下,每个配置的检查结果都是 0 个错误。
其他差异:
tsc-rs在 VS Code 上报告 10 个错误,在 Sentry 上报告 2 个。TypeScript 7.1.0-dev(typescript@next)逐行报告了相同的错误。tsc-rs移植的是 7.1 的开发版修订,包含 7.0.2 没有的检查。tsc6 在 VS Code 上报告 9 个错误。
测量方式:Apple M4 Pro(12 核,48 GB),macOS 26.5.1。使用 hyperfine(https://github.com/sharkdp/hyperfine),1 次预热后取 5 次运行的中位数,参数为 --noEmit --incremental false。每个检查器使用其默认线程数。tsc 7 和 tsc-rs 作为原生二进制运行,不使用 npm 启动器。tsc 6 运行在 Node 24.19 上,使用 16 GB 堆,因为在 VS Code 和 Sentry 上使用默认堆会内存不足。
版本:tsc-rs 0.1.0,TypeScript 7.0.2 和 6.0.3,Bun canary bd599f5af。检查行数为 tsc 7 的 --extendedDiagnostics 计数(含 .d.ts 文件)。上方的 T3 Code 基准测试使用相同的机器和方法。
有四个应用需要修改才能在 tsc 7 下零错误通过检查,其他方面没有变化:
- Excalidraw:移除
baseUrl,因为 TS 7 移除了该选项。 - TypeORM:
moduleResolution从node改为nodenext,因为 TS 7 移除了node。 - VS Code:添加其 postinstall 安装的
electron类型定义。 - Playwright:添加其构建过程生成的源码文件。
有两个应用未列入表格:
- rxjs main 需要先构建其 workspace 包。
- date-fns 使用项目引用(project references)。在该项目中,
tsc -p和bun check执行的工作不同。
脚本位于 scripts/bench-apps:先运行 setup.sh,然后 run.sh 和 summary.py,T3 Code 使用 t3code.sh。
已知问题
-
在某些 monorepo 中,workspace 包的源文件可以通过
node_modules和直接导入两种途径访问。在这种情况下,tsc-rs可能会为其中更多文件输出结果,并对它们报告 TS6059(文件不在rootDir下)。tsc是基于时间来判定的,因此其结果在多次运行之间会变化。tsc-rs每次运行都给出相同结果(即 TypeScript 6 的结果)。 -
在
tsc -b中,当一个项目在没有项目引用的情况下导入另一个项目的输出时,tsc-rs可能读取到旧的或缺失的输出(TS2305 或 TS2307),而tsc能读取到新的输出。当项目只需要重新写入其输出文件时会出现这种情况。添加项目引用即可修复。 -
在编辑器中,长时间编辑会话中内存会缓慢增长(每 1000 次编辑约增长 20 MiB)。在我们测量的会话中,它始终低于
tsc的内存占用。 -
tsc-rs --version打印的是它所移植的 TypeScript 版本(7.1.0-dev),而非 npm 包版本。编译器会用该版本号来匹配typesVersions。
开发
crates/ts_goport 是编译器。它有两个子 crate:goport_util 和 goport_lsproto,位于 crates/ts_goport/parts,并使用 crates/ts_goport/libs 中的库文件。
tools/ts_ast_codegen 生成 crates/ts_goport/src/astdata,tools/ts_diagnostics_codegen 生成 crates/ts_goport/src/diagnostics/catalog.rs 和 crates/ts_goport/src/diag.rs。
crates/ts_wasm 是 WebAssembly 构建(npm/wasm)。
./scripts/run-cargo-capped.sh build --release -p ts_goport --bins
./scripts/verify.sh
可执行文件为 goport(类型检查)和 tsgo(Go 版 tsgo 命令行)。Go 基准测试的运行方式为:TS_GO_REPO=/path/to/typescript-go ./scripts/run-cargo-capped.sh test -p ts_goport --test go_baselines。
- 移植规则:crates/ts_goport/PORTING.md
- 测量与验证脚本:scripts/goport
- npm 包与发布:npm/README.md
- 类型检查器工作规则:AGENTS.md、问责规则 和已保存状态
- 项目起源:docs/history.md
发布
推送一个以 v 开头的 tag(例如 v0.1.0)。发布工作流会构建、打包并测试各包,发布到 npm 并创建 GitHub Release。稳定版本发布到 dist-tag latest,预发布版本(v0.2.0-beta.1)发布到 next 并创建 GitHub 预发布。参见 npm/README.md。
许可证
MIT。本次移植保留了所移植代码的许可证和声明:TypeScript(Apache-2.0)以及 Go 标准库的部分代码(BSD-3-Clause)。参见 NOTICE.md。
相似文章
tsrs:TypeScript 向 Rust 的移植
Cloudflare 与 VoidZero 携手 Max Schwenk,在 Oxc 工具链中孵化 tsrs——一个忠实移植到 Rust 的 TypeScript 编译器。据称其速度最高可提升 8 倍,内存占用比 TypeScript 7.0 减少约 70%,同时语言设计仍完全由 TypeScript 团队掌控。
@evanyou:又一个 TS 的 Rust 移植版加入了群聊
又一个 TypeScript 项目正在被移植到 Rust,这反映了为提升性能而用 Rust 重写流行 JS/TS 工具的持续趋势。
@tolgaogzz: 我和我的最佳 codex 将 eslint-plugin-svelte 移植到了 Rust,运行速度提升约 330 倍,所有规则的所有测试用例均通过…
一位开发者借助 Codex 将 eslint-plugin-svelte 移植到 Rust,实现了约 330 倍的速度提升,同时通过了所有测试用例。
将React编译器移植到Rust
一项将React编译器移植到Rust的计划,旨在提高性能并与Rust生态系统集成。
为何构建 Rust LSP 如此困难
这篇博客文章阐述了构建 Rust 语言服务器协议(LSP)的技术挑战,借鉴了作者在 Rust Glancer 上的经验以及 rust-analyzer 的见解。