Декораторы в JavaScript прошли длительный путь стандартизации в рамках TC39. Изначально они появились как экспериментальная возможность, затем закрепились в экосистеме TypeScript и Babel, а позже стали частью официального предложения ECMAScript, но с существенными изменениями синтаксиса и семантики.
Ключевая особенность развития — существование нескольких несовместимых поколений спецификации, которые продолжают сосуществовать в реальных проектах:
Это привело к тому, что современные компиляторы, включая SWC, вынуждены поддерживать несколько режимов трансформации.
Legacy-декораторы — это де-факто стандарт, который долгое время использовался в TypeScript и Babel до пересмотра спецификации TC39.
Object.defineProperty
reflect-metadata и
emitDecoratorMetadata в TypeScript
Пример поведения:
function readonly(target, key, descriptor) {
descriptor.writable = false;
return descriptor;
}
Legacy-модель тесно связана с TypeScript и его опцией:
experimentalDecorators: true
emitDecoratorMetadata: true
Новая спецификация декораторов (часто называемая “TC39 decorators”) радикально отличается от legacy-модели.
Главное отличие — разделение этапов декорирования:
context, описывающий тип декорируемого
элемента
Пример новой модели:
function logged(value, context) {
if (context.kind === "method") {
return function (...args) {
console.log("call:", context.name);
return value.apply(this, args);
};
}
}
Объект context содержит:
kind — тип сущности (class,
method, field, getter,
setter)
name — имя метода или поля
access — объект доступа к значению
static — статический ли элемент
private — признак приватности
Эта модель делает декораторы более предсказуемыми и безопасными.
Legacy:
target, key,
descriptor
TC39:
value и context
Legacy:
TC39:
SWC реализует декораторы как часть трансформационного слоя
jsc.transform.
Основная особенность SWC — явное управление версией спецификации через конфигурацию.
Основной блок конфигурации:
{
"jsc": {
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
}
}
}
Опция включает поддержку legacy-модели.
experimentalDecorators
Включает генерацию метаданных:
reflect-metadata
SWC поддерживает выбор версии спецификации через параметр уровня трансформации.
Типичная конфигурация:
{
"jsc": {
"transform": {
"decoratorVersion": "2022-03"
}
}
}
Возможные режимы:
context
SWC выполняет преобразование через Rust-реализацию AST-проходов.
Разбор синтаксиса декораторов в AST
Классификация типа декоратора:
Выбор стратегии трансформации (legacy или TC39)
Генерация вспомогательных функций
Инъекция runtime-хелперов
В legacy-режиме SWC генерирует обёртки:
__decorate
__metadata
__param
В TC39-режиме используется более компактная модель без классических helper-цепочек, но с runtime-вызовами декораторов через контекст.
@sealed
class Example {}
Трансформируется в:
@sealed
class Example {}
В новой модели:
value класса
descriptor
writable, enumerable,
configurable
context.addInitializer
Пример:
function trace(value, context) {
if (context.kind === "method") {
return function (...args) {
console.log(context.name);
return value.apply(this, args);
};
}
}
Важное отличие современных декораторов — полноценная поддержка полей класса.
Если одновременно включены:
поведение становится неопределённым, поскольку модели трансформации несовместимы.
SWC часто используется как замена TypeScript-компилятора, но:
SWC старается сохранять совместимость с Babel:
@babel/plugin-proposal-decorators
Одно из ключевых преимуществ SWC:
Это особенно заметно в проектах с большим количеством классов:
В реальных кодовых базах выбор версии декораторов определяется:
SWC выступает как универсальный слой, позволяющий: