Custom Decorator

Learn how to create and use custom decorators in Vercube to extend functionality and create reusable patterns

Vercube provides a powerful decorator system that allows you to create custom decorators for your application. Custom decorators extend the BaseDecorator class and can be used to add metadata, modify behavior, or inject dependencies into your classes and methods.

How Decorators Work

Decorators in Vercube are created using the createDecorator() factory function. Each decorator is a class that extends BaseDecorator and is instantiated by the IOC container, which means you can use dependency injection inside your decorators.

import { BaseDecorator, createDecorator, Inject } from '@vercube/di';

class MyDecorator extends BaseDecorator<MyOptions> {
  @Inject(SomeService)
  private someService!: SomeService;
  
  public override created(): void {
    // Called when decorator is initialized
  }
  
  public override destroyed(): void {
    // Called when decorator is cleaned up
  }
}

export function MyDecorator(options?: MyOptions): Function {
  return createDecorator(MyDecorator, options);
}

BaseDecorator Class

The BaseDecorator class is the foundation for all custom decorators. It provides access to the decorated element and lifecycle hooks.

Properties

PropertyTypeDescription
optionsTOptions object passed to the decorator
instanceanyThe class instance that is decorated
prototypePThe class prototype that is decorated
propertyNamestringName of the decorated property or method
descriptorPropertyDescriptorProperty descriptor of the decorated element
propertyIndexnumberParameter index (for parameter decorators)

Lifecycle Methods

created()

Called when the decorator is created and ready to be used. Use this to set up event listeners, register hooks, or perform initialization logic.

public override created(): void {
  // Initialize your decorator
  console.log(`Decorator applied to ${this.propertyName}`);
}

destroyed()

Called when the decorator is destroyed. Use this for cleanup tasks like unregistering listeners or clearing timers. This is called at the end of SSR requests or when a component is destroyed.

public override destroyed(): void {
  // Cleanup resources
  this.unsubscribe();
}

Creating a Custom Decorator

Basic Example

Here's a simple decorator that logs method calls:

import { BaseDecorator, createDecorator } from '@vercube/di';

interface LogDecoratorOptions {
  level?: 'debug' | 'info' | 'warn';
  prefix?: string;
}

class LogMethodDecorator extends BaseDecorator<LogDecoratorOptions> {
  private originalMethod!: Function;
  
  public override created(): void {
    // Store the original method
    this.originalMethod = this.descriptor.value;
    
    // Replace with wrapped version
    const options = this.options;
    const methodName = this.propertyName;
    
    this.descriptor.value = function(...args: any[]) {
      const prefix = options?.prefix || '';
      console.log(`${prefix}[${methodName}] called with:`, args);
      
      const result = this.originalMethod.apply(this, args);
      
      console.log(`${prefix}[${methodName}] returned:`, result);
      return result;
    };
  }
}

/**
 * Logs method calls with arguments and return values
 */
export function LogMethod(options?: LogDecoratorOptions): Function {
  return createDecorator(LogMethodDecorator, options);
}

Usage:

import { Controller, Get } from '@vercube/core';
import { LogMethod } from './decorators/LogMethod';

@Controller('/users')
export class UserController {
  
  @LogMethod({ prefix: '[UserController] ' })
  @Get('/:id')
  async getUser(req: Request, params: { id: string }) {
    return { id: params.id, name: 'John' };
  }
}

API Reference

createDecorator()

Factory function to create a decorator from a BaseDecorator class.

function createDecorator<T>(
  DecoratorClass: typeof BaseDecorator<T>,
  options?: T
): Function

Parameters:

ParameterTypeDescription
DecoratorClasstypeof BaseDecorator<T>The decorator class to instantiate
optionsTOptions to pass to the decorator

Returns: A decorator function that can be applied to classes, methods, or parameters.

BaseDecorator<T, P>

Abstract base class for all decorators.

abstract class BaseDecorator<T = any, P = any> {
  public options: T;
  public instance: any;
  public prototype: P;
  public propertyName: string;
  public descriptor: PropertyDescriptor;
  public propertyIndex: number;
  
  public created(): void;
  public destroyed(): void;
}

Type Parameters:

ParameterDescription
TType of the options object
PType of the prototype (for advanced use cases)
Previous

Custom Plugin

Learn how to create and use custom plugins in Vercube to extend functionality and add new features

Next