Bun 和 Node.js 原生 TypeScript 支持怎么选?
Node.js 22.6+ 内置 TypeScript 类型擦除,23.6 起默认开启;Bun 则原生一等支持 TypeScript。本文从开发流程、TS 特性兼容、包管理、测试、生产部署全面对比两条路线。
想用零依赖的官方运行时直接跑 TypeScript 选 Node.js 原生支持(类型擦除,不做类型检查);想要"运行时+包管理+打包+测试"一体化的极速体验选 Bun。关键差异:Node 的方案只做类型擦除(类型检查交给编辑器/tsc),Bun 同样不做类型检查但工具链整合度更高、执行更快。
两种"原生支持"的真实含义
Node.js 从 22.6 引入 --experimental-strip-types,23.6 起类型擦除成为默认行为:node app.ts 直接运行,TS 注解在执行前被剥离。注意它不做类型检查——tsc --noEmit 或编辑器的类型错误提示依然是你质量保障的一部分。
Bun 从诞生第一天就一等支持 TypeScript:直接执行、无需配置,背后是 Zig 编写的转译器,速度极快。同样地,它也不做类型检查——两个运行时都遵循"转译与检查分离"的现代共识。
开发流程对比
- 启动速度:对比时应分别测量首次运行和重复执行,固定依赖、机器与输入数据;
- Watch 模式:两者都内置(
node --watch/bun --hot),Bun 的热重载响应更快; - REPL:两者都有,
bun repl直接支持 TypeScript 语法,体验更完整。
TypeScript 特性兼容性
两者都只支持"可擦除"的 TypeScript——运行时无关的类型注解都可以。不支持需要代码生成的特性(除非启用转换模式):
enum(枚举):Node 需--experimental-transform-types才支持,Bun 直接支持;- 参数属性(constructor 的
private name)、命名空间:同样需要转换模式; - 装饰器:按 TS5 标准实现,两者均部分支持。
工程建议:坚持用 erasableSyntaxOnly 风格的 TS(接口、类型注解、as const、satisfies),避开 enum 和参数属性——这样代码在任何运行时和构建工具下都能跑。
包管理与生态整合
Bun 自带包管理器(bun install,极快)、打包器(bun build)、测试运行器(bun test,Jest 兼容 API)——开箱即全家桶。Node 原生方案则搭配你选择的外部工具:npm/pnpm、tsx/vitest 等,组合自由度更高,生态兼容性(尤其是一些依赖 Node 内部 API 的包)也最稳。
生产部署的现实考量
Node 原生 TypeScript 的生产价值在于消除构建步骤:容器镜像里不用装 TypeScript 编译链,部署流程与 JS 完全一致。Bun 的生产部署需要 Bun 运行时镜像,冷启动和内存表现优秀,但你要接受一个相对年轻的运行时(对 Node 特定 API 的兼容性需验证,如部分原生 addon)。
务实结论:Node 生态项目、求稳选 Node 原生方案;新项目、CLI 工具、边缘函数(Bun 的冷启动优势巨大)可以大胆用 Bun。
常见问题(FAQ)
Q:类型擦除安全吗?类型错误会不会带到生产?
类型擦除只是把注解剥离,不做检查——这正是官方刻意的设计(检查归 tsc/编辑器)。在 CI 中加 tsc --noEmit 步骤即可保证类型错误进不了生产,运行时与构建工具链彻底解耦。
Q:Node 原生 TS 和 tsx 还有必要用后者吗?
Node 23.6+ 的简单脚本场景原生已够用;tsx 仍有优势:支持任意 TS 特性(enum 等)、兼容老版本 Node、更快的转译器与路径别名支持。大型项目的开发体验 tsx 依然更顺滑。
Q:Bun 支持 Node 的所有 API 吗?
覆盖度已经很高且持续补齐(官方有兼容性追踪),常用 API(fs、http、crypto、stream)都可用。踩坑高发区是冷门原生 addon 和依赖 Node 内部实现的库——迁移前用测试套全面验证。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。