ts-rust 发布:由 LLM 将 TypeScript 编译器、检查器和 LSP 移植到 Rust
Port of the TypeScript compiler, checker and lsp to Rust, by LLM
ts-rust(tsc-rs)将 microsoft/TypeScript(Go 实现)的编译器、类型检查器和语言服务器移植为 Rust,作者称全部代码由 LLM 编写,本人未读过代码。
原文给出了完整基准数据和兼容性测试结果,读者可以据此评估这个 Rust 版 TypeScript 检查器是否适合接入现有项目。
ts-rust(又名 tsc-rs)
我想看看 LLM 能否把 TypeScript 编译器、检查器和 lsp 移植到 Rust。事实证明它们可以。
这花费了超过 42 万美元的 token,但你大概用约 2 万美元就能完成(见下文)
动机
- 测试模型能力
- 打造一个快速的 TypeScript 类型检查器
- 打造一个能在 WASM 中高性能运行的 ts 检查器
- 梗图
警告
这是早期版本。在我们测试过的所有真实项目中,它都实现了 100% 兼容。对于绝大多数应用来说,它应当可以作为直接替代品使用。参见已知问题。
另外值得一提的是:这代码我一行都没读过。
安装
事先警告,我完全不知道这到底能不能用。
npm install -D tsc-rs npx tsc-rs -p tsconfig.json
进展如何?
我用了大量 OpenAI 模型来尝试完成这次移植。总共,我用 GPT-5.6 Sol 和 GPT 6 Astra 消耗了超过 40 万美元 API 定价的 token。它们在数月的 /goal 循环中写了超过 130 万行 Rust,兼容度却始终没能超过 84% 左右。
当我看到我的 Claude Code 额度几乎没怎么消耗时,我想把 Opus 5.5 扔进去应该会很有趣。它 10 小时就做出了一个可用的 v0。
我以为它会继续使用 Codex 模型写的代码。我错了。Opus 5.5 是从零开始的。它用 1/10 的时间就比 Astra 走得更远。
我让它继续跑下去,它确实做到了。总 token 花费为两周内约 24,047 美元的 API 支出。我用的是我的 Claude 账户,折算下来大约是我 200 美元套餐每周限额的925% 到 983%。
确实很贵,但考虑到 typescript-go 投入了那么多工作,也不算太糟。
“垃圾分界线”
以下所有内容都是由我的 LLM 写的,不是我。
这到底是什么?
ts-rust 是微软原生 TypeScript 编译器的直接移植版,后者用 Go 编写(microsoft/TypeScript,原为 typescript-go)。它保留了 Go 的算法和行为,并拥有相同的命令行(tsc)、语言服务器和 API。
安装
npm install -D tsc-rs npx tsc-rs -p tsconfig.json
tsc-rs 接受与 tsc 相同的选项。npm 包名为 tsc-rs,以免与 typescript 包冲突。每个发布版本还附带各平台的独立归档:tsc 二进制文件及其旁边的 lib 文件。
平台:Linux x64(静态,适用于任何发行版)和 macOS arm64。Windows 和 Linux arm64 尚不可用。
要在 VS Code 中使用它,请参阅 npm 包 README。
Effect 诊断
tsc-rs 内置了 Effect 语言服务诊断(代码 377xxx),因此 Effect 项目不需要第二个编译器。它们与 TypeScript 诊断来自同一次检查,语言服务器也会显示它们。它们仅在 tsconfig 含有该插件时运行,与 @effect/language-service 一样:
{ "compilerOptions": { "plugins": [{ "name": "@effect/language-service" }] } }规则、选项和 @effect-diagnostics 注释是 Effect-TS/tsgo 0.46.1 的移植。语言服务器的编辑器功能(快速修复、重构、悬停、补全)尚未移植。
状态
该移植固定在一个上游修订版本,即 microsoft/TypeScript 673a5f17d713(2026-09-29,TypeScript 7.1.0-dev;UPSTREAM.md),并与该修订版本的 Go 版本进行比较。要进行比较,请使用 typescript@7.1.0-dev.20260929.1,而不是 7.0.x 或 @typescript/native-preview。此构建同样表现出的差异属于上游行为,当移植更新到更新的固定版本时就会消失。
- 结果相同。TanStack Query 核心和 Hono 的检查诊断与 Go 完全一致。所有 181,711 个移植的 Go 测试均通过。语言服务器和 API 的应答在 oracle 测试集上与 Go 一致。
- 更快。在 60 个开源项目上,类型检查耗时约为 Go 版本的一半(几何平均值)。预览包是在 CI 中构建的,未启用 PGO 和 BOLT,因此比上述实测构建更慢。
- 真实项目。在 120 个开源仓库上,命令行输出与 Go 版本的差异仅在于下述问题,以及 Go 自身输出在多次运行间发生变化之处。
基准测试:T3 Code
对 T3 Code 进行完整类型检查,并与 tsc 6、tsc 7 以及 Bun 中新的 bun check 进行对比。T3 Code 使用了 Effect,因此有两种情况:不带 Effect 诊断和带 Effect 诊断。每次耗时均为五个 T3 Code 项目的总和。越低越快。
不带 Effect 诊断
| 检查器 | 时间 | 对比 tsc 6 |
对比 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 诊断
| 检查器 | 时间 | 对比 tsc 6 |
对比 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 项目需要第二遍检查。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 修复了该问题。
测量方式:与下文真实应用相同的机器和方法,并添加了 --composite false(apps/web 为 composite)。T3 Code 位于 cd41c4ad,项目为 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。
基准测试:真实应用
使用 tsc 6(JavaScript 编译器)、tsc 7(Go 编译器)、tsc-rs 和 bun check 对六个开源应用进行完整类型检查。倍数是相对于 tsc 6 的加速比。时间越低越快。
| 应用 | 检查行数 | tsc 6 |
tsc 7 |
tsc-rs |
bun check |
|---|---|---|---|---|---|
| VS Code | 3.75M | 54.56s | 6.84s (8.0×) | 4.20s (13.0×) | 1.62s (33.7×) |
| Sentry(前端) | 2.11M | 58.76s | 7.90s (7.4×) | 4.46s (13.2×) | 3.14s (18.7×)* |
| Playwright | 585k | 4.48s | 0.66s (6.8×) | 0.34s (13.2×) | 0.18s (25.0×) |
| Excalidraw | 449k | 5.32s | 0.80s (6.7×) | 0.70s (7.6×) | 0.18s (29.0×) |
| TypeORM | 386k | 3.86s | 0.55s (7.0×) | 0.36s (10.7×) | 0.19s (20.0×) |
| tRPC(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×(几何平均值)。除 tRPC 外,bun check 在每个应用上都是最快的。
* 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,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 下以 0 错误进行检查。其他没有变化:
- Excalidraw:没有
baseUrl,因为 TS 7 移除了它。 - TypeORM:
moduleResolution从node改为nodenext,因为 TS 7 移除了node。 - VS Code:其 postinstall 添加的
electron类型定义。 - Playwright:其构建生成的源文件。
有两个应用不在表中:
- rxjs main 需要先构建其工作区包。
- date-fns 使用项目引用。在那里,
tsc -p和bun check做不同的工作。
脚本位于 scripts/bench-apps:setup.sh <dir>,然后是 run.sh <dir> 和 summary.py <dir>,T3 Code 用 t3code.sh <dir>。
已知问题
- 在某些 monorepo 中,工作区包的源文件既可以通过
node_modules访问,也可以通过直接导入访问。在那里,tsc-rs可能为比tsc更多的这些文件写出输出,并报告 TS6059(文件不在rootDir下)。tsc通过计时来决定这一点,因此它自己的结果在运行之间会变化。tsc-rs在每次运行中给出相同的结果(TypeScript 6 的结果)。 - 在
tsc -b中,当一个项目导入另一个项目的输出而没有项目引用时,tsc-rs可能读取到旧的或缺失的输出(TS2305 或 TS2307),而tsc读取到新的输出。当项目只需要写出其输出时会发生这种情况。添加引用即可修复。 - 在编辑器中,长时间编辑会话期间内存会缓慢增长(每 1,000 次编辑约 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 中的 lib 文件。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<version>(例如 v0.1.0)。发布工作流 构建、打包并测试这些包,将它们发布到 npm 并创建 GitHub 发布。稳定版本进入 dist-tag latest,预发布版本(v0.2.0-beta.1)进入 next 和 GitHub 预发布。参见 npm/README.md。
许可证
MIT。该移植保留了它所移植代码的许可证和声明:TypeScript(Apache-2.0)和 Go 标准库的部分内容(BSD-3-Clause)。参见 NOTICE.md。
来源:Hacker News:AI 热帖 · github.com