Skip to content

TypeScript

Oxc transformer 支持将 TypeScript 转换为 JavaScript。

js
import { transform } from "oxc-transform";

const result = await transform("lib.ts", sourceCode, {
  typescript: {
    jsxPragma: "React.createElement",
    jsxPragmaFrag: "React.Fragment",
    onlyRemoveTypeImports: false,
    allowNamespaces: true,
    removeClassFieldsWithoutInitializer: false,
    rewriteImportExtensions: false,
    optimizeConstEnums: false,
    optimizeEnums: false,
  },
});

verbatimModuleSyntax

默认情况下,TypeScript 移除未使用导入的语义与 JavaScript 规范不同。 verbatimModuleSyntax 选项告诉 TypeScript 与 JavaScript 规范保持一致。

如果您使用此选项,请确保将 typescript.onlyRemoveTypeImports 选项设置为 true

js
import { transform } from "oxc-transform";

const result = await transform("lib.ts", sourceCode, {
  typescript: {
    onlyRemoveTypeImports: true,
  },
});

useDefineForClassFields

TypeScript 曾经对类字段的语义与 JavaScript 规范不同。 useDefineForClassFields 选项告诉 TypeScript 与 JavaScript 规范保持一致。 如果 tsconfig 中的 target 选项设置为 es2022 或更高版本,此选项默认启用。

如果您禁用此选项,请确保将 typescript.removeClassFieldsWithoutInitializer 选项和 assumptions.setPublicClassFields 设置为 true

js
import { transform } from "oxc-transform";

const result = await transform("lib.ts", sourceCode, {
  typescript: {
    removeClassFieldsWithoutInitializer: true,
  },
  assumptions: {
    setPublicClassFields: true,
  },
});

装饰器

Oxc transformer 支持转换旧版装饰器。这在 TypeScript 中称为实验性装饰器。

如果您在 tsconfig 中使用 experimentalDecorators 选项,可以使用 decorator.legacy 选项。 如果您在 tsconfig 中使用 emitDecoratorMetadata 选项,可以使用 decorator.emitDecoratorMetadata 选项。

js
import { transform } from "oxc-transform";

const result = await transform("lib.ts", sourceCode, {
  decorator: {
    legacy: true,
    emitDecoratorMetadata: true,
  },
});

装饰器元数据:需要类型推断的类型将回退到 Object

由于缺少完整的类型推断功能,如果 Oxc transformer 无法计算装饰器元数据的类型,它将回退到 Object 类型。

例如,以下代码将被转换为:

ts
import { Something1 } from "./somewhere";

type Something2 = Exclude<string | number, string>;

export class Foo {
  @test
  foo(input1: Something1, input2: Something2) {}
}
js
// 省略辅助函数
import { Something1 } from "./somewhere";
var _ref;
export class Foo {
  foo(input1, input2) {}
}
_decorate(
  [
    test,
    _decorateMetadata("design:type", Function),
    _decorateMetadata("design:paramtypes", [
      typeof (_ref = typeof Something1 !== "undefined" && Something1) === "function"
        ? _ref
        : Object,
      Object, 
    ]),
    _decorateMetadata("design:returntype", void 0),
  ],
  Foo.prototype,
  "foo",
  null,
);
js
// 省略辅助函数
var _a;
import { Something1 } from "./somewhere";
export class Foo {
  foo(input1, input2) {}
}
__decorate(
  [
    test,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [
      typeof (_a = typeof Something1 !== "undefined" && Something1) === "function" ? _a : Object,
      Number, 
    ]),
    __metadata("design:returntype", void 0),
  ],
  Foo.prototype,
  "foo",
  null,
);

此行为与 TypeScript 在使用外部类型时的行为一致。

您可以通过调用 Reflect.metadata 显式设置类型:

ts
import { Something1 } from "./somewhere";

type Something2 = Exclude<string | number, string>;

export class Foo {
  @test
  @Reflect.metadata("design:paramtypes", [Something1, Number])
  foo(input1: Something1, input2: Something2) {}
}
js
// 省略辅助函数
import { Something1 } from "./somewhere";
var _ref;
export class Foo {
  foo(input1, input2) {}
}
_decorate(
  [
    test,
    Reflect.metadata("design:paramtypes", [Something1, Number]),
    _decorateMetadata("design:type", Function),
    _decorateMetadata("design:paramtypes", [
      typeof (_ref = typeof Something1 !== "undefined" && Something1) === "function"
        ? _ref
        : Object,
      Object,
    ]),
    _decorateMetadata("design:returntype", void 0),
  ],
  Foo.prototype,
  "foo",
  null,
);

TSX

也支持转换 TSX 文件。 详见 JSX 转换

重写导入扩展名

如果您在 tsconfig 中使用 rewriteRelativeImportExtensions 选项,可以使用 typescript.rewriteImportExtensions 选项。

  • "rewrite"true:将 .ts.tsx 重写为 .js.mts 重写为 .mjs.cts 重写为 .cjs
  • "remove":完全移除 .ts/.tsx/.mts/.cts 扩展名。
  • false(默认):不更改。
js
import { transform } from "oxc-transform";

const result = await transform("lib.ts", sourceCode, {
  typescript: {
    rewriteImportExtensions: "rewrite", // 或 "remove", true, false
  },
});

优化枚举

Oxc transformer 可以通过在使用位置内联枚举成员值来优化枚举。

  • optimizeConstEnums:内联 const enum 值并移除声明。
  • optimizeEnums:当所有成员都满足 const enum 约束(即其值可静态求值)时,内联常规(非 const)枚举成员访问。当所有成员可求值且不存在对枚举作为运行时值的引用时,非导出的枚举声明也会被移除。
js
import { transform } from "oxc-transform";

const result = await transform("lib.ts", sourceCode, {
  typescript: {
    optimizeConstEnums: true,
    optimizeEnums: true,
  },
});

声明文件

在转换输出旁边生成 .d.ts 声明文件。源文件必须符合所有 isolatedDeclarations 要求。

js
import { transform } from "oxc-transform";

const result = await transform("lib.ts", sourceCode, {
  typescript: {
    declaration: {
      stripInternal: false,
    },
  },
});

console.log(result.declaration); // .d.ts 内容
console.log(result.declarationMap); // 声明 source map(如果启用了 sourcemap)

注意事项

隔离模块

由于 Oxc transformer 独立转换每个文件,某些 TypeScript 功能不受支持。 为了避免使用不支持的功能,您应该在 tsconfig.json 文件中启用 isolatedModules 选项。

部分命名空间支持

TypeScript 有一个称为命名空间的旧功能。虽然建议新项目使用 ES 模块,但 Oxc transformer 对命名空间有部分支持。

不支持使用 varlet 导出变量

不支持使用 varlet 导出变量。

ts
namespace Foo {
  export let bar = 1; 
}
console.log(Foo.bar);

解决方法是使用 const。如果您需要变量可变,请使用具有内部可变性的对象:

ts
namespace Foo {
  export const bar = { value: 1 }; 
}
console.log(Foo.bar.value);

同名命名空间之间不共享作用域

ts
namespace Foo {
  export const bar = 1;
}
namespace Foo {
  export const baz = bar;
}
js
let foo;
(function (_Foo) {
  const bar = (_Foo.bar = 1);
})(Foo || (Foo = {}));
(function (_Foo2) {
  const baz = (_Foo2.baz = bar); 
})(Foo || (Foo = {}));
js
var Foo;
(function (Foo) {
  Foo.bar = 1;
})(Foo || (Foo = {}));
(function (Foo) {
  Foo.baz = Foo.bar; 
})(Foo || (Foo = {}));

在此示例中,第二个命名空间中的 bar 引用对于 TypeScript 编译器输出指向第一个命名空间中的 bar 变量,但对于 Oxc transformer 输出则不然。

解决方法是通过命名空间对象显式引用:

ts
namespace Foo {
  export const bar = 1;
}
namespace Foo {
  export const baz = Foo.bar; 
}