Decorator Factories
In this page:
Creating a Decorator Factory
A decorator factory is just a regular function that returns a decorator, which lets you call it with arguments like @Log(info) instead of being stuck with one fixed, argument-less @Log.
Example: Creating a Decorator Factory
function Log(level: string) {
return function (target: any, context: ClassMethodDecoratorContext) {
console.log(`[${level}] decorating ${String(context.name)}`);
};
}
class Service {
@Log("info")
run() {}
}
new Service();
Factories with Numeric Options
Passing a numeric option — such as a maximum retry count or a cache duration in milliseconds — into the factory lets the same underlying decorator logic behave differently depending on how it's invoked on each class member.
Example: Factories with Numeric Options
function retry(maxAttempts: number) {
return function (target: any, context: ClassMethodDecoratorContext) {
console.log(`Will retry up to ${maxAttempts} times`);
};
}
class Api {
@retry(3)
fetchData() {}
}
new Api();
Factories with Multiple Options
A factory can accept several options at once, commonly through a single configuration object argument, so callers can opt into just the settings they care about instead of remembering a long positional argument list.
Example: Factories with Multiple Options
interface Options { level: string; prefix: string; }
function configurableLog(options: Options) {
return function (target: any, context: ClassMethodDecoratorContext) {
console.log(`[${options.level}] ${options.prefix}: ${String(context.name)}`);
};
}
class Service {
@configurableLog({ level: "debug", prefix: "svc" })
run() {}
}
new Service();
Reusable Validation Factories
Building a factory around a validation rule (like a regex or a range) turns one decorator into a reusable library you can apply across many different classes with different constraints, rather than writing bespoke validation each time.
Example: Reusable Validation Factories
function matches(pattern: RegExp) {
return function (value: undefined, context: ClassFieldDecoratorContext) {
return function (this: any, initial: string) {
if (!pattern.test(initial)) throw new Error("Invalid value");
return initial;
};
};
}
class User {
@matches(/^[a-z]+$/)
username = "ravi";
}
console.log(new User().username);
Factory Evaluation
The factory function itself runs immediately at decoration time to produce the actual decorator, while the decorator it returns only runs later when the class is defined — mixing up these two evaluation moments is a common source of bugs.
Example: Factory Evaluation
function factory(label: string) {
console.log("Factory running now, at decoration time:", label);
return function (target: any, context: ClassMethodDecoratorContext) {
console.log("Decorator running later, when class is defined");
};
}
class Example {
@factory("early")
method() {}
}
new Example();
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: