Compatible Decorators
Goal
Create one decorator that works with both TypeScript decorator transforms.
Implementation
import 'reflect-metadata';
import { Methods } from '@litert/decorator/compatible';
export const track = Methods.create({
legacy: (ctx) => {
Reflect.defineMetadata('tracked', ctx.name, ctx.constructor);
},
modern: (_method, ctx) => {
ctx.metadata!['tracked'] = ctx.name;
},
});Note: The
legacycallback usesreflect-metadata(Reflect.defineMetadata) to store metadata against the class constructor. Themoderncallback writes toctx.metadatabecause modern member decorators do not receive the owning class constructor or prototype. Do not usegetMetadataContainerin legacy callbacks. It is designed for reading modern decorator metadata after the class has been defined.
Dispatch model
| Runtime shape | Callback used |
|---|---|
| Legacy method decorator arguments | legacy(ctx) |
| Modern method decorator arguments | modern(method, ctx) |
The compatible helper validates the received arguments first. If the decorator is applied to the wrong kind of element, it throws TypeError.
Example code
Compatible decorators have two layers: definitions (the implementations) and consumers (the code that applies them under each TypeScript transform). Every row below links to three files — one definition shared by both consumer builds.
| Decorator kind | Definition | Legacy consumer | Modern consumer |
|---|---|---|---|
| Class | Class.ts | Class.ts | Class.ts |
| Method | Method.ts | Method.ts | Method.ts |
| Property | Property.ts | Property.ts | Property.ts |
| Accessor | Accessor.ts | Accessor.ts | Accessor.ts |
| Getter | Getter.ts | Getter.ts | Getter.ts |
| Setter | Setter.ts | Setter.ts | Setter.ts |
| Static method | StaticMethod.ts | StaticMethod.ts | StaticMethod.ts |
| Static property | StaticProperty.ts | StaticProperty.ts | StaticProperty.ts |
| Static accessor | StaticAccessor.ts | StaticAccessor.ts | StaticAccessor.ts |
| Static getter | StaticGetter.ts | StaticGetter.ts | StaticGetter.ts |
| Static setter | StaticSetter.ts | StaticSetter.ts | StaticSetter.ts |