From harness-claude
Implements class, method, property, and parameter decorators with reflect-metadata in TypeScript. Use for logging, validation, caching, dependency injection in NestJS, Angular, TypeORM.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Implement class, method, and property decorators with reflect-metadata in TypeScript
Implements GOF Decorator pattern in TypeScript: class-based for objects (encryption, compression) and function-based for async functions (retry). Use to add stackable runtime behaviors without subclassing.
Masters advanced TypeScript types, generics, conditional types, decorators, strict configs for enterprise architectures and production type safety hardening.
Masters advanced TypeScript typing with generics, conditional types, decorators, strict configs, and enterprise patterns for architecture design and inference optimization.
Share bugs, ideas, or general feedback.
Implement class, method, and property decorators with reflect-metadata in TypeScript
tsconfig.json:{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
function Sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@Sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
}
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${propertyKey} with`, args);
const result = original.apply(this, args);
console.log(`${propertyKey} returned`, result);
return result;
};
}
class Calculator {
@Log
add(a: number, b: number): number {
return a + b;
}
}
function MinLength(min: number) {
return function (target: any, propertyKey: string) {
let value: string;
Object.defineProperty(target, propertyKey, {
get: () => value,
set: (newValue: string) => {
if (newValue.length < min) throw new Error(`${propertyKey} must be at least ${min} chars`);
value = newValue;
},
});
};
}
class User {
@MinLength(3)
name: string = '';
}
function Inject(token: string) {
return function (target: any, propertyKey: string | undefined, parameterIndex: number) {
const existingInjections = Reflect.getOwnMetadata('injections', target) || [];
existingInjections.push({ index: parameterIndex, token });
Reflect.defineMetadata('injections', existingInjections, target);
};
}
function Retry(attempts: number, delay: number) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = async function (...args: any[]) {
for (let i = 0; i < attempts; i++) {
try {
return await original.apply(this, args);
} catch (e) {
if (i === attempts - 1) throw e;
await new Promise((r) => setTimeout(r, delay));
}
}
};
};
}
class ApiClient {
@Retry(3, 1000)
async fetchData(): Promise<Data> {
/* ... */
}
}
class Service {
@Log // Applied second (outer)
@Retry(3, 100) // Applied first (inner)
async getData(): Promise<Data> {
/* ... */
}
}
TypeScript decorators are an implementation of the TC39 Stage 3 decorators proposal (legacy version). They execute at class definition time, not at runtime method invocation.
Decorator execution order:
emitDecoratorMetadata uses reflect-metadata to emit type information that decorators can read at runtime. This powers dependency injection in NestJS and TypeORM. Install reflect-metadata and import it once at the entry point.
TC39 Stage 3 decorators (2023+): TypeScript 5.0+ supports the new standard decorators syntax WITHOUT experimentalDecorators. The new syntax is different from the legacy syntax — they use a different function signature and do not support parameter decorators or metadata emission by default.
Legacy vs Stage 3:
function Dec(target, key, descriptor) — widely used in NestJS, Angular, TypeORMfunction Dec(value, context) — new standard, limited framework adoption so farexperimentalDecorators: trueTrade-offs:
emitDecoratorMetadata increases bundle size with reflection metadataany for targetshttps://typescriptlang.org/docs/handbook/decorators.html