Nub 运行整个 TypeScript 接口,不只是 Node 内置类型剥离接受的 可擦除子集。以 .ts.tsx.mts.cts 结尾的文件直接执行:Nub 通过 module.registerHooks() 加载钩子用其基于 oxc 的转译器转译它们,然后将结果交给 Node。

nub index.ts
nub server.tsx

转译在 Node 看到代码之前发生,所以本页的转换在 Nub 支持的每个 Node 版本(18.19+)上都有效。唯一的例外是 source map;参见下方 Source map

类型被剥离,不被检查

Nub 不做类型检查——类型被剥离以供执行。在编辑器和 CI 中保留 tsc --noEmit 进行类型验证。node_modules 内的文件也从不被转译;它们完全按包发布的方式加载。

不可擦除语法

enumnamespace、参数属性和 import = 等语法需要转换,不只是类型移除——Node 的类型剥离拒绝所有这些。Nub 的转译器作为正常流水线的一部分发射运行时形式。

enum Color { Red, Green, Blue }

namespace Geometry {
  export const PI = 3.14159;
}

class User {
  constructor(public id: string, private name: string) {}
}

import fs = require("node:fs");

你通过编写来选择语法;Nub 让它运行。

JSX 和装饰器各有自己的页面:参见 JSX 了解 .jsx / .tsx 运行时和 tsconfig 配置,装饰器了解旧版 experimentalDecorators 形式和 emitDecoratorMetadata

普通 JavaScript

你项目的普通 JavaScript——.js.mjs.cjs——通过相同的流水线。Nub 的 Node 下限无法原生解析的现代语法以与 .ts 文件中完全相同的方式降级,所以相同的源码无论扩展名如何行为一致:using / await usingv 标志(unicode-sets)正则如 /\p{Letter}/v 和装饰器都能运行。

// app.js — 在 Nub 支持的每个 Node 上运行
using handle = openHandle();
const letters = /\p{Letter}/v;

没有需要降级内容的文件原封不动交给 Node——逐字节,不重新格式化也不加 source map 尾部——所以不需要转换的普通 .js 就是你写的文件。node_modules 内的文件从不被转译;它们按包发布的方式加载,在每个层级上。

.js 文件中的 JSX 不在范围内——使用 .jsx。Nub 将 .js 解析为 JavaScript 而非 JSX,所以 < 是比较运算符,不是元素。

显式资源管理

显式资源管理——usingawait using 声明——在 Nub 的整个 Node 下限上运行。较旧的 Node(Node 22 的 V8)无法原生解析 using——它是硬 SyntaxError——所以 Nub 的转译器在 Node 看到之前将其降级为基于辅助函数的形式。

class Handle {
  [Symbol.dispose]() { console.log("disposed"); }
}

{
  using h = new Handle();
  console.log("using h");
}
console.log("after scope");
$ nub resource.ts
using h
disposed
after scope

降级目标为 es2022——仍重写 using 的最高目标,同时保持 Node 22 已支持的一切(顶层 await、类字段、私有方法)不变。释放辅助函数通过 Nub 内嵌的运行时解析;你不需要安装任何东西。

Source map

Nub 为每个转译文件生成内联 source map 并注入 --enable-source-maps,所以未捕获的错误和 console.trace() 打印指向你原始 TypeScript 源码和行号的帧——而非生成的 JS。默认开启;不需要记住标志,且在 nub --inspect.ts 源码中设置的断点正确落地。

$ nub app.ts
/path/to/app.ts:2
	throw new Error("kaboom");
	^

Error: kaboom
    at boom (/path/to/app.ts:2:8)
    at Object.<anonymous> (/path/to/app.ts:4:1)

堆栈帧报告 app.ts:2:8——你源码中的行,而非转译输出。要关闭它,传递 --no-enable-source-maps

Source map 在每个支持的 Node 版本上注入,除了 26.2.x 补丁带,在该带中 Node 回归使得开启 source map 时无消息的 assert(false) 重新抛出为 TypeError 而非 AssertionError。在 26.2.x 上 Nub 不注入该标志,所以该处的堆栈跟踪不会被重映射。其他所有版本(18.19 到 26.1,以及 26.3+)都获得 source map。