用 LLM 将 TypeScript 编译器、类型检查器和 LSP 移植到 Rust

Hacker News Top 工具

摘要

一个项目展示了完全借助 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 6vs tsc 7
bun check4.07s15.4×3.95× 更快
tsc-rs7.25s8.6×2.22× 更快
tsc 716.10s3.9×基准
tsc 662.63s基准3.89× 更慢

含 Effect 诊断

检查器耗时vs tsc 6vs tsc 7 + Effect
tsc-rs(Effect 内置)11.13s12.5×1.89× 更快
tsc 7 + @effect/tsgo21.07s6.6×基准
bun check,再运行 effect-tsgo diagnostics37.60s3.7×1.78× 更慢
tsc 6 + @effect/language-service138.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 6tsc 7tsc-rsbun check
VS Code(https://github.com/microsoft/vscode/tree/3f07e1aba32acacb8b08ae91bfdc954b580ad1fd)3.75M54.56s6.84s (8.0×)4.20s (13.0×)1.62s (33.7×)
Sentry(https://github.com/getsentry/sentry/tree/8294650589dbd26f230c73f4ab26b62a68aede8f)(前端)2.11M58.76s7.90s (7.4×)4.46s (13.2×)3.14s (18.7×)*
Playwright(https://github.com/microsoft/playwright/tree/d469960fdfc461e2d5795a3fa48a58a52a91ecaf)585k4.48s0.66s (6.8×)0.34s (13.2×)0.18s (25.0×)
Excalidraw(https://github.com/excalidraw/excalidraw/tree/53973c3a423fbd75a4ce68107786b4fcb90e4968)449k5.32s0.80s (6.7×)0.70s (7.6×)0.18s (29.0×)
TypeORM(https://github.com/typeorm/typeorm/tree/c64a1f052fc39f6688b6b73b83d065d7147ba8bb)386k3.86s0.55s (7.0×)0.36s (10.7×)0.19s (20.0×)
tRPC(https://github.com/trpc/trpc/tree/d756e591a5e37ef20b8d75ecd4d736c195497289)(server 包)209k1.10s0.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 没有的检查。
  • tsc 6 在 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。

发布

推送一个以 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 的移植

Hacker News Top

Cloudflare 与 VoidZero 携手 Max Schwenk,在 Oxc 工具链中孵化 tsrs——一个忠实移植到 Rust 的 TypeScript 编译器。据称其速度最高可提升 8 倍,内存占用比 TypeScript 7.0 减少约 70%,同时语言设计仍完全由 TypeScript 团队掌控。

为何构建 Rust LSP 如此困难

Lobsters Hottest

这篇博客文章阐述了构建 Rust 语言服务器协议(LSP)的技术挑战,借鉴了作者在 Rust Glancer 上的经验以及 rust-analyzer 的见解。