跳到正文
scriptc

普通的 TypeScript,
编译成原生可执行文件

产物里没有 Node,没有 V8,也没有 JavaScript 引擎。不需要注解,不需要方言,不需要特殊标准库。

fib.ts
function fib(n: number): number {
  return n < 2 ? n : fib(n - 1) + fib(n - 2);
}
console.log(fib(30));

$ scriptc run fib.ts
832040

$ scriptc build fib.ts -o fib && ./fib
832040

三个层级,层级就是承诺

scriptc 逐个构造地判断哪些能编译为原生代码,并且会告诉你结果。程序里的每个构造恰好落在下面一个层级。

  • 静态编译

    默认层级

    原生代码,没有引擎。你写的那份 TypeScript 直接过真正的 TypeScript 编译器做类型检查,再落到原生代码上。stdout、stderr 与退出码和 Node 下逐字节一致,分歧只有一份带编号的记录清单。

    约 320KB · 除系统 C 库外不链接任何东西

  • 动态运行

    --dynamic

    内嵌 quickjs-ng 引擎,只为无法静态化的部分工作:npm 依赖自带的 JS,以及 any 类型代码。每个回穿进静态代码的值都在运行时校验,说谎的类型抛出可捕获的 TypeError,而不是破坏内存。

    内嵌引擎约 620KB · 静态仍是默认

  • 拒绝编译

    编译期失败

    其余一切在编译期停下,附带具体的错误码、一段代码帧,通常还有一个改写提示。没有任何代码会被静默地编译错误。

    例如 SC2013 · SC3002

覆盖率报告 会让你程序里的层级分布一目了然。

编译产物可以逐段停下查看

用 --emit 停在任意一段,不同类型的产物累积在 .scriptc/ 目录里。

  1. TypeScript解析与类型检查
  2. 带类型的 IRhello.ir.json
  3. C可读的 C 代码
  4. LLVM IRhello.ll
  5. 原生 / WASMhello · hello.wasm
$ scriptc build hello.ts --emit=c >/dev/null
$ ls .scriptc/
hello.c
hello.ir.json

$ scriptc build hello.ts --emit=llvm >/dev/null
$ ls .scriptc/
hello.c
hello.ir.json
hello.ll
两个完全对齐的机加工金属立方体,象征逐字节一致的差分验证

正确性由两个门禁保证

差分测试
语料库里每个程序既在 Node 下运行,也作为原生二进制运行,stdout、stderr 与退出码必须逐字节一致。服务器用实时客户端分别驱动两种实现。
内存安全通道
整个语料库在 AddressSanitizer 下重跑,并做一次引用计数审计。内存泄漏和释放后使用都算构建失败。

工作原理 说明了这条管线背后的架构。

装上就能试

编译器需要 Node.js 24 或更高版本。源码级产物(ir、c、llvm)只要 Node 就能生成,它产出的可执行文件不依赖 Node。

$ npm install -g scriptc
$ scriptc run hello.ts
hello, world