TypeScript
Трансформер Oxc поддерживает преобразование TypeScript в JavaScript.
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 выравнивает поведение со спецификацией JS.
Если она включена, задайте typescript.onlyRemoveTypeImports: true.
import { transform } from "oxc-transform";
const result = await transform("lib.ts", sourceCode, {
typescript: {
onlyRemoveTypeImports: true,
},
});useDefineForClassFields
Раньше у TypeScript была другая семантика полей класса, чем в спецификации JavaScript. Опция useDefineForClassFields выравнивает поведение. По умолчанию она включается, если target в tsconfig — es2022 или выше.
Если вы её отключаете, задайте typescript.removeClassFieldsWithoutInitializer и assumptions.setPublicClassFields: true.
import { transform } from "oxc-transform";
const result = await transform("lib.ts", sourceCode, {
typescript: {
removeClassFieldsWithoutInitializer: true,
},
assumptions: {
setPublicClassFields: true,
},
});Декораторы
Трансформер Oxc поддерживает legacy-декораторы — в TypeScript они называются experimental decorators.
При experimentalDecorators в tsconfig используйте decorator.legacy. При emitDecoratorMetadata — decorator.emitDecoratorMetadata.
import { transform } from "oxc-transform";
const result = await transform("lib.ts", sourceCode, {
decorator: {
legacy: true,
emitDecoratorMetadata: true,
},
});Метаданные декораторов: типы, требующие вывода типов, станут Object
Из-за неполной поддержки вывода типов трансформер подставит тип Object, если не может вычислить тип для метаданных декоратора.
Например, следующий код преобразуется так:
import { Something1 } from "./somewhere";
type Something2 = Exclude<string | number, string>;
export class Foo {
@test
foo(input1: Something1, input2: Something2) {}
}// 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,
);// 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:
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) {}
}// 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.
Переписывание расширений импорта
Если в tsconfig включён rewriteRelativeImportExtensions, используйте typescript.rewriteImportExtensions.
"rewrite"илиtrue:.tsи.tsx→.js,.mts→.mjs,.cts→.cjs."remove": расширения.ts/.tsx/.mts/.ctsполностью убираются.false(по умолчанию): без изменений.
import { transform } from "oxc-transform";
const result = await transform("lib.ts", sourceCode, {
typescript: {
rewriteImportExtensions: "rewrite", // or "remove", true, false
},
});Оптимизация enum
Трансформер может инлайнить значения членов enum в местах использования.
optimizeConstEnums: инлайнит значенияconst enumи удаляет объявление.optimizeEnums: инлайнит обращения к обычным (не const) enum, если все члены удовлетворяют ограничениям const enum (значения статически вычислимы). Неэкспортируемые enum удаляются, если все члены вычислимы и на enum как на значение времени выполнения нет ссылок.
import { transform } from "oxc-transform";
const result = await transform("lib.ts", sourceCode, {
typescript: {
optimizeConstEnums: true,
optimizeEnums: true,
},
});Декларации (declaration)
Генерация файлов .d.ts вместе с результатом преобразования. Исходный файл должен удовлетворять всем требованиям isolatedDeclarations.
import { transform } from "oxc-transform";
const result = await transform("lib.ts", sourceCode, {
typescript: {
declaration: {
stripInternal: false,
},
},
});
console.log(result.declaration); // the .d.ts content
console.log(result.declarationMap); // the declaration source map (if sourcemap is enabled)Ограничения
Изолированные модули
Трансформер обрабатывает каждый файл отдельно, поэтому часть возможностей TypeScript недоступна. Чтобы их избегать, включите isolatedModules в tsconfig.json.
Частичная поддержка namespace
В TypeScript есть устаревшие namespaces. Для новых проектов рекомендуют ES-модули; в Oxc поддержка namespace частичная.
Экспорт переменной через var или let не поддерживается
namespace Foo {
export let bar = 1;
}
console.log(Foo.bar);Обходной путь — const. Если нужна мутабельность, используйте объект с внутренней мутабельностью:
namespace Foo {
export const bar = { value: 1 };
}
console.log(Foo.bar.value);Пространства имён с одинаковым именем не делят одну область видимости
namespace Foo {
export const bar = 1;
}
namespace Foo {
export const baz = bar;
}let foo;
(function (_Foo) {
const bar = (_Foo.bar = 1);
})(Foo || (Foo = {}));
(function (_Foo2) {
const baz = (_Foo2.baz = bar);
})(Foo || (Foo = {}));var Foo;
(function (Foo) {
Foo.bar = 1;
})(Foo || (Foo = {}));
(function (Foo) {
Foo.baz = Foo.bar;
})(Foo || (Foo = {}));Здесь во втором namespace ссылка bar в выводе компилятора TypeScript указывает на bar из первого namespace, а в выводе Oxc — нет.
Явно обращайтесь через объект namespace:
namespace Foo {
export const bar = 1;
}
namespace Foo {
export const baz = Foo.bar;
}