Two Decorators, One Keyword, Zero Compatibility

A team wanted to write a standard decorator for a new logging library and switched off experimentalDecorators across the repo. Their NestJS service started with undefined dependencies in every controller, because Nest relies on the metadata that only the legacy decorators emit.

TypeScript has two decorator features that share one syntax: the legacy experimental decorators that frameworks such as NestJS and Angular are built on, and the standard TC39 decorators supported since TypeScript 5.0. Below is how each works, field, accessor and class decorators under the new proposal, where the metadata went, and how to decide which to use.

If you have changed decorator flags and broken a framework
  • You've seen Reflect.getMetadata('design:paramtypes', ...) return undefined and had no idea why
  • NestJS or TypeORM examples use decorators that look nothing like the ones in the TypeScript 5 release notes
  • You tried turning off experimentalDecorators in an existing app and half the codebase stopped compiling
  • You're not sure whether emitDecoratorMetadata is doing anything in your current build

Neither proposal is going away soon — legacy decorators still power most dependency-injection frameworks in production. Knowing which one you're looking at, and why they can't be mixed, saves a specific kind of confusing afternoon.