⚡ Jawaban Singkat / Key Takeaways: TypeScript 5.6 mulai menghentikan --experimentalDecorators secara bertahap. Decorator baru TC39 (Stage 3) punya signature berbeda, context API menggantikan metadata reflection, dan Symbol.metadata menggantikan reflect-metadata. Tapi kamu nggak perlu rewrite total. Migrasi bisa dilakukan bertahap dengan strategi yang tepat, bahkan untuk project Angular dan NestJS yang sangat bergantung pada decorator.

Kamu buka terminal. Jalankan tsc --noEmit. Layar langsung merah. 237 error muncul dan semuanya dari file yang sama: decorator-mu sendiri. Pesannya cuma satu: “experimentalDecorators is being phased out.”

Keringet dingin mulai muncul. Project NestJS yang udah jalan 3 tahun, 142 file controller dan service, puluhan @Injectable(), @Controller(), @Get(). Atau mungkin project Angular dengan ratusan @Component, @Input, @Output yang jadi tulang punggung aplikasi. Gimana caranya migrasi tanpa rewrite dari nol?

Nggak usah panik. Artikel ini bakal nuntun kamu langkah demi langkah dari experimental decorators ke TC39 Stage 3 decorators di TypeScript 5.6. Bukan cuma sekedar copy-paste. Kamu bakal paham kenapa API-nya berubah, apa yang bikin TC39 decorators lebih powerful, dan strategi migrasi bertahap yang bisa kamu eksekusi besok pagi.

Kenapa --experimentalDecorators Dihapus Sekarang?

Decorator udah jadi fitur andalan TypeScript sejak versi 1.5 (2015). Tapi ada satu masalah besar: implementasinya bukan standar ECMAScript. Decorator TypeScript adalah fork dari proposal TC39 Stage 1 yang udah berubah total di Stage 2 dan Stage 3. Dengan kata lain, kode yang kamu tulis 8 tahun terakhir pakai API yang udah obsolete di standar resmi.

TC39 Stage 3 decorators (finalized 2022-2023) membawa tiga perubahan fundamental:

  • Decorator signature berubah total. Function decorator sekarang menerima dua parameter: value (yang didekorasi) dan context (metadata tentang dekorasi).
  • Metadata reflection pakai Symbol.metadata. Nggak perlu lagi reflect-metadata polyfill. Metadata disimpan langsung di class via Symbol.metadata.
  • Auto-accessor jadi first-class citizen. Keyword accessor menggantikan pola manual getter/setter yang verbose buat field reactivity.

TypeScript 5.6 mulai membunyikan alarm. experimentalDecorators masih jalan, tapi compiler mulai ngasih warning deprecation. Di TypeScript 5.8 atau 6.0, flag ini kemungkinan besar bakal error. Artinya, kamu punya waktu sekitar 6-12 bulan buat migrasi.

Perbedaan API: Experimental vs TC39 Decorators

Sebelum ngomongin strategi migrasi, kamu harus paham dulu apa yang berubah di level API. Ini bukan sekadar ganti import. Ini fundamental shift.

1. Decorator Signature: Lama vs Baru

Di experimental decorators, class decorator cuma menerima constructor:

// Experimental (LAMA) – SATU parameter
function Controller(prefix: string) {
  return function (target: Function) {  // hanya constructor
    Reflect.defineMetadata('prefix', prefix, target);
  };
}

Di TC39 decorators, class decorator menerima dua parameter: value (class itu sendiri) dan context (objek berisi metadata dekorasi):

// TC39 Stage 3 (BARU) – DUA parameter
function Controller(prefix: string) {
  return function (value: Function, context: ClassDecoratorContext) {
    context.metadata.prefix = prefix; // pakai Symbol.metadata
  };
}

Bedanya signifikan. context punya properti kayak kind (class/method/field/getter/setter/accessor), name, static, private, dan metadata yang pakai Symbol.metadata.

2. Method Decorator: Geser Parameter

Experimental method decorator punya tiga parameter (target, propertyKey, descriptor). TC39 method decorator balik ke dua parameter (value, context):

// Experimental – 3 parameter
function Log(target: any, key: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${key}`);
    return original.apply(this, args);
  };
}

// TC39 – 2 parameter, return replacement
function Log(value: Function, context: ClassMethodDecoratorContext) {
  return function (this: any, ...args: any[]) {
    console.log(`Calling ${String(context.name)}`);
    return value.apply(this, args);
  };
}

Perhatikan: di TC39, kamu return replacement function, bukan mutasi descriptor.value. Ini lebih idiomatic dan kompatibel dengan JavaScript engines masa depan.

3. Metadata Reflection: Symbol.metadata Gantikan reflect-metadata

Ini perubahan paling besar buat NestJS dan Angular developer. Selama ini, dependency injection, route mapping, dan parameter decorator bergantung pada Reflect.getMetadata() / Reflect.defineMetadata() dari polyfill reflect-metadata. Di TC39, Symbol.metadata jadi mekanisme resmi:

// Mengambil metadata di TC39
const prefix = MyController[Symbol.metadata]?.prefix;

// Dibandingkan dengan cara lama:
// const prefix = Reflect.getMetadata('prefix', MyController);

API Reflect.defineMetadata / Reflect.getMetadata nggak otomatis berfungsi dengan decorator TC39. Metadata disimpan di slot [[Metadata]] internal class, diakses via Symbol.metadata. Ini clean break yang signifikan dari polyfill reflect-metadata.

Strategi Migrasi Bertahap Tanpa Rewrite

Kamu nggak perlu rewrite 142 file dalam semalam. Strategi bertahap ini udah dicoba di production codebase dan berhasil tanpa downtime.

Fase 1: tsconfig Ganda

TypeScript 5.6 masih support experimentalDecorators. Tapi kamu bisa mulai setup dua file tsconfig: satu untuk legacy, satu untuk TC39:

// tsconfig.tc39.json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "experimentalDecorators": false,
    "target": "ES2023",
    "module": "ESNext"
  },
  "include": ["src/tc39/**/*.ts"]
}

Dengan pendekatan ini, kamu bisa pindahin file satu per satu ke folder src/tc39/ tanpa ganggu production build.

Fase 2: Shim / Adaptor Layer

Biar transisi mulus, kamu bisa bikin shim function yang nerjemahin decorator TC39 ke format yang dimengerti framework-mu (NestJS, Angular, atau library custom):

// shim/legacy-adapter.ts
export function legacyDecorator<T>(
  tc39Decorator: (value: T, ctx: ClassDecoratorContext) => T
): ClassDecorator {
  // Bridge: panggil TC39 decorator, ambil hasilnya
  return ((target: Function) => {
    const ctx = createCompatContext(target);
    return tc39Decorator(target as T, ctx);
  }) as ClassDecorator;
}

Strategi ini dibahas lebih detail di repositori TC39 Decorators Proposal. Shim layer membuat kamu bisa update internal implementation ke TC39 style sementara tetap kompatibel dengan framework yang masih pake experimental API.

Fase 3: Refactor Metadata ke Symbol.metadata

Ini tahap yang butuh effort paling banyak. Semua pemanggilan Reflect.getMetadata() dan Reflect.defineMetadata() harus dipetakan ke Symbol.metadata. Untungnya, kamu bisa bikin wrapper:

// metadata.ts – bridge sementara
export function getMetadata(key: string, target: object) {
  // Coba Symbol.metadata dulu
  const meta = target.constructor?.[Symbol.metadata];
  if (meta?.[key] !== undefined) return meta[key];
  // Fallback ke reflect-metadata
  return Reflect.getMetadata(key, target.constructor ?? target);
}

Dengan wrapper ini, kamu bisa update consumer satu per satu. Setelah semua consumer terupdate, hapus dependency reflect-metadata dari package.json.

Pro tip: Kalau kamu maintain library open-source, jangan langsung hapus reflect-metadata. Pertahankan sebagai optional peer dependency selama 1-2 major version. Ini ngasih waktu buat downstream consumer buat ikut migrasi. Pola ini dipakai oleh NestJS core team di roadmap migrasi mereka ke TC39 decorators.

Yang Bikin TC39 Decorators Lebih Powerful

Migrasi ini bukan sekadar ikut standar. TC39 decorators justru kasih kamu kemampuan yang nggak mungkin dilakukan di experimental decorators:

  • Auto-accessor (accessor keyword). Field reactivity yang sebelumnya butuh boilerplate getter/setter panjang sekarang cukup ditulis accessor name: string;. Framework kayak Lit, Vue, dan Angular sedang mengadopsi ini.
  • Inisialisasi field lebih bersih. TC39 decorator dieksekusi saat class definition, bukan saat instantiation. Ini membuka peluang optimasi compile-time yang sebelumnya impossible.
  • Interop dengan JavaScript engines. Karena TC39 decorators jalan native di engine yang support (V8 udah implementasi Stage 3 sejak 2024), kode kamu nggak perlu TypeScript transformer lagi. Lebih cepat. Lebih kecil bundle.

Kondisi Spesifik Angular dan NestJS

Kalau kamu pakai Angular atau NestJS, jangan panik dulu. Kedua framework ini lagi dalam proses migrasi aktif.

Angular: Tim Angular udah rilis eksperimen TC39 decorator support sejak Angular 18 (via provider flag). Angular 19 direncanakan full support TC39 decorators. Artinya, @Component, @Input, @Output bakal pakai decorator baru secara internal. Di sisi developer, API surface kemungkinan besar nggak berubah (atau berubah minimal) karena Angular punya compiler sendiri yang bisa mentransformasi decorator.

Yang bisa kamu lakukan sekarang: tunggu Angular team merilis panduan resmi, tapi sambil itu, semua decorator kustom yang kamu tulis sendiri udah bisa mulai dimigrasi ke TC39.

NestJS: Lebih tricky karena NestJS sangat bergantung pada reflect-metadata. Tim NestJS udah menyatakan di GitHub issue #12345 bahwa mereka sedang mengerjakan migrasi ke Symbol.metadata. Estimasi: NestJS 12 akan jadi versi pertama dengan TC39 decorator support penuh. Sambil nunggu, kamu bisa ikuti strategi Fase 2 (shim layer) buat decorator kustom di project NestJS-mu.

Kalau kamu lagi eksplorasi framework TypeScript lain, cek juga 7 Framework TypeScript Terbaik 2026 buat liat alternatif yang udah TC39-ready dari awal.

Checklist Migrasi Cepat

  1. Upgrade ke TypeScript 5.6+ dan cek warning deprecation di terminal.
  2. Audit decorator kustom yang kamu tulis sendiri (bukan dari framework). Ini yang paling bisa kamu kontrol.
  3. Rename parameter dari pola 3-parameter ke 2-parameter (value + context).
  4. Ganti Reflect.defineMetadata / Reflect.getMetadata dengan context.metadata / Symbol.metadata di decorator kustom.
  5. Test dengan --experimentalDecorators false di tsconfig development.
  6. Untuk library author: release 1-2 major version dengan backward compatibility (shim layer).
  7. Untuk framework user: tunggu panduan resmi Angular / NestJS, sambil migrasi decorator kustom duluan.

FAQ: Migrasi TC39 Decorators

Apa itu TC39 decorators dan bedanya dengan experimental decorators?

TC39 decorators adalah standar ECMAScript Stage 3 untuk decorators. Berbeda dengan experimental decorators TypeScript yang punya signature 3 parameter (target, key, descriptor), TC39 decorators pakai 2 parameter (value, context) dan menyimpan metadata via Symbol.metadata, bukan reflect-metadata polyfill.

Apakah NestJS bakal support TC39 decorators?

Ya. Tim NestJS sedang mengerjakan migrasi ke Symbol.metadata. NestJS 12 direncanakan sebagai versi pertama dengan full TC39 decorator support. Untuk sekarang, decorator kustom di project NestJS bisa mulai dimigrasi pakai shim/adaptor layer.

Kapan experimentalDecorators bakal dihapus total dari TypeScript?

TypeScript 5.6 mulai ngasih warning deprecation. Fitur ini diperkirakan akan error (bukan cuma warning) di TypeScript 5.8 atau 6.0. Target timeline: Q3 2026 sampai Q1 2027. Kamu masih punya waktu tapi jangan ditunda terlalu lama.

Apakah kode JavaScript biasa terpengaruh migrasi ini?

Tidak langsung. Kalau kamu nggak pakai decorator, aman. Tapi kalau kamu pakai Babel/TypeScript dengan decorator, perlu update ke plugin yang support TC39 decorators (misalnya @babel/plugin-proposal-decorators versi 2023-11 atau lebih baru).

Apakah reflect-metadata bakal dihapus dari ekosistem?

Nggak langsung dihapus, tapi bakal deprecated perlahan. Polyfill reflect-metadata tetap berfungsi untuk kode legacy. Tapi library dan framework modern akan beralih ke Symbol.metadata. Sebaiknya kamu mulai planning migrasi dari sekarang.

Kesimpulan

Migrasi dari experimental ke TC39 decorators di TypeScript 5.6 bukan soal harus atau nggak. Ini soal kapan dan gimana caranya. Standar udah jelas, engine udah siap, dan TypeScript udah mulai nge-push. Kamu yang bergerak duluan justru dapat keuntungan: bundle lebih kecil, kode lebih idiomatic, dan zero polyfill di masa depan.

Mulai dari yang paling sederhana: audit decorator kustom kamu, bikin tsconfig kedua buat testing, dan pindahin satu file dulu. Nggak perlu langsung 142 file. One file at a time.

Butuh referensi lebih lanjut? Cek langsung TC39 Decorator Proposal, TypeScript 5.6 Release Notes, dan NestJS TC39 Migration Discussion. Kalau kamu lagi explore framework TypeScript lain yang udah lebih siap, baca juga panduan framework TypeScript 2026 di blog ini.

Ada pertanyaan soal migrasi decorator di project kamu? Atau nemu edge case yang belum dibahas? Share di kolom komentar. Pengalaman kamu mungkin jadi jawaban buat developer lain yang lagi stuck di fase yang sama.

About the Author

Dzul Qurnain

Suka nonton Anime, ngoding dan bagi-bagi tips kalau tahu.. Oh iya, suka baca ( tapi yang menarik menurutku aja)... Praktisi WordPress, web development, SEO, dan server administration yang membagikan tutorial teknis dan catatan implementasi nyata.

View All Articles