Decorator is very powerful feature in Typescript. It can add additional information or steps to support annotating or modifying. It empowers Typescript with AOP(Aspect-oriented-programming), DI (Dependency Injection) or even meta programming. It's widely used in Angular and Nestjs. If you are familiar with Java SpringBoot, you find them very similar. Whereas in Java, Decorator is called Annotation.
To enable decorator feature, we need to enable experimentalDecorators
in tsconfig.json
first.
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
There are 5 types of decorators including Class Decorators, Method Decorators, Accessor Decorators, Property Decorators, Parameter Decorators. Each decorator has a slightly different group of parameters. If there are more than 1 type of decorators are added, they will be executed in a well defined order:
For further information of decorators, you can visit this official documentation.
Here is a playground for Typescript decorators.
Add the action to MetadataArgsStorage
;
export function Get(route?: string | RegExp, options?: HandlerOptions): Function {
return function (object: Object, methodName: string) {
getMetadataArgsStorage().actions.push({
type: 'get',
target: object.constructor,
method: methodName,
options,
route,
});
};
}
createExecutor(driver: T, options: RoutingControllerOptions = {}): void {
return new RoutingControllers(driver, options)
.initialize()
.registerInterceptors(interceptorClasses)
.registerMiddlewares('before', middlewareClasses)
.registerControllers(controllerClasses)
.registerMiddlewares('after', middlewareClasses);
}
Register the actions of controllers to driver;
registerControllers(classes?: Function[]): this {
const controllers = this.metadataBuilder.buildControllerMetadata(classes);
controllers.forEach(controller => {
controller.actions.forEach(actionMetadata => {
const interceptorFns = this.prepareInterceptors([
...this.interceptors,
...actionMetadata.controllerMetadata.interceptors,
...actionMetadata.interceptors,
]);
this.driver.registerAction(actionMetadata, (action: Action) => {
return this.executeAction(actionMetadata, action, interceptorFns);
});
});
});
this.driver.registerRoutes();
return this;
}
registerAction(actionMetadata: ActionMetadata, executeCallback: (options: Action) => any): void {
this.express[actionMetadata.type.toLowerCase()](
...[route, routeGuard, ...beforeMiddlewares, ...defaultMiddlewares, routeHandler, ...afterMiddlewares]
);
}