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
// omit helper functions
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
// omit helper functions
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
// omit helper functions
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 transform

重写导入扩展名

如果你在 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); // 声明源映射(如果启用了 sourcemap)

注意事项

独立模块

由于 Oxc transformer 会独立转换每个文件,因此某些 TypeScript 特性不受支持。 为避免使用不受支持的特性,你应该在 tsconfig.json 文件中启用 isolatedModules 选项。

部分命名空间支持

TypeScript 有一个称为 namespaces 的旧特性。虽然新项目推荐使用 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 = {}));

在这个示例中,TypeScript 编译器输出中第二个命名空间里的 bar 引用指向第一个命名空间中的 bar 变量,但 Oxc transformer 的输出中不是这样。

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

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