Decorators
Overview
Use these factories when you are building a decorator, rather than using an existing one such as @Get. Your callback receives the decorated target first and the arguments from the decorator call afterwards.
These are TypeScript legacy decorators: enable experimentalDecorators. They do not implement the standard JavaScript decorator context API. Examples that call Reflect.defineMetadata also need import "reflect-metadata" before use; importing the package root already loads it.
Start with MakeClassDecorator for a one-target example. Consult the combined factory table only when the same decorator must support several targets.
Name a class with a decorator
This decorator stores a label when the class is declared. target is the class constructor; name is the value passed to @Label.
import { MakeClassDecorator } from "@antelopejs/interface-core/decorators";
const labels = new WeakMap<Function, string>();
const Label = MakeClassDecorator((target: Function, name: string) => {
labels.set(target, name);
});
@Label("users")
class UserController {}
const label = labels.get(UserController); // "users"
The factories do not run request-time behavior by themselves. Your integration decides when to read stored values or invoke a decorated method.
Import
import {
MakeClassDecorator,
MakePropertyDecorator,
MakeMethodDecorator,
MakeParameterDecorator,
} from "@antelopejs/interface-core/decorators";
Types
The module exports several utility types used throughout the decorator system:
| Type | Description |
|---|---|
Func<A, R> | Generic function type with arguments A and return type R |
Class<T, A> | Class constructor that creates instances of type T |
ClassDecorator<C> | Decorator applied to class constructors |
PropertyDecorator | Decorator applied to class properties |
MethodDecorator | Decorator applied to class methods and accessors |
ParameterDecorator | Decorator applied to method parameters |
Single-target decorator factories
MakeClassDecorator
Creates a decorator factory that targets classes. The handler receives the decorated class as its first argument, followed by any factory parameters.
import { MakeClassDecorator } from "@antelopejs/interface-core/decorators";
const Entity = MakeClassDecorator((target: Function, tableName: string) => {
Reflect.defineMetadata("table", tableName, target);
});
@Entity("users")
class User {
name!: string;
}
MakePropertyDecorator
Creates a decorator factory that targets properties. The handler receives the target object and property key, followed by factory parameters.
import { MakePropertyDecorator } from "@antelopejs/interface-core/decorators";
const Column = MakePropertyDecorator(
(target: any, key: PropertyKey, columnName: string) => {
const columns = Reflect.getOwnMetadata("columns", target) || [];
columns.push({ key, columnName });
Reflect.defineMetadata("columns", columns, target);
},
);
class User {
@Column("user_name")
name!: string;
}
MakeMethodDecorator
Creates a decorator factory that targets methods and accessors. The handler receives the target object, method key, and property descriptor, followed by factory parameters.
import { MakeMethodDecorator } from "@antelopejs/interface-core/decorators";
const Log = MakeMethodDecorator(
(
target: any,
key: PropertyKey,
descriptor: PropertyDescriptor,
level: string,
) => {
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`[${level}] Calling ${String(key)}`);
return original.apply(this, args);
};
},
);
class Service {
@Log("info")
process() {
// ...
}
}
MakeParameterDecorator
Creates a decorator factory that targets method parameters. The handler receives the target object, method key, and parameter index, followed by factory parameters.
import { MakeParameterDecorator } from "@antelopejs/interface-core/decorators";
const Inject = MakeParameterDecorator(
(target: any, key: PropertyKey, index: number, token: string) => {
const injections = Reflect.getOwnMetadata("injections", target, key) || [];
injections[index] = token;
Reflect.defineMetadata("injections", injections, target, key);
},
);
class Controller {
handle(@Inject("db") db: any) {
// ...
}
}
Multi-target decorator factories
For decorators that apply to multiple targets, the module provides combined factory functions. These detect the decorator context automatically based on the number and types of arguments received.
| Factory | Targets |
|---|---|
MakePropertyAndClassDecorator | Properties and classes |
MakeMethodAndClassDecorator | Methods and classes |
MakeMethodAndPropertyDecorator | Methods and properties |
MakeMethodAndPropertyAndClassDecorator | Methods, properties, and classes |
MakeParameterAndClassDecorator | Parameters and classes |
MakeParameterAndPropertyDecorator | Parameters and properties |
MakeParameterAndPropertyAndClassDecorator | Parameters, properties, and classes |
MakeParameterAndMethodDecorator | Parameters and methods |
MakeParameterAndMethodAndClassDecorator | Parameters, methods, and classes |
MakeParameterAndMethodAndPropertyDecorator | Parameters, methods, and properties |
MakeParameterAndMethodAndPropertyAndClassDecorator | Parameters, methods, properties, classes |
Example: method and class decorator
import { MakeMethodAndClassDecorator } from "@antelopejs/interface-core/decorators";
const Track = MakeMethodAndClassDecorator(
(
target: any,
key: PropertyKey | undefined,
descriptor: PropertyDescriptor | undefined,
category: string,
) => {
if (descriptor) {
// Applied to a method
const original = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`[${category}] ${String(key)} called`);
return original.apply(this, args);
};
} else {
// Applied to a class
Reflect.defineMetadata("trackCategory", category, target);
}
},
);
@Track("api")
class ApiController {
@Track("endpoint")
getUsers() {
// ...
}
}
When applied to a class, the key and descriptor arguments are undefined. When applied to a method, all three arguments are provided.