Cómo crear decoradores TypeScript personalizados

Los decoradores son una característica de TypeScript que permite modificar clases, métodos, propiedades o parámetros en tiempo de ejecución. Son funciones especiales que brindan capacidades de metaprogramación. En TypeScript, los decoradores se utilizan a menudo en marcos como Angular para mejorar la funcionalidad. Este artículo explica cómo crear decoradores personalizados paso a paso.

Tipos de decoradores en TypeScript

Hay cuatro tipos principales de decoradores en TypeScript:

  • Decoradores de clases
  • Decoradores de métodos
  • Decoradores de accesorios
  • Decoradores de propiedades

Habilitar decoradores en TypeScript

Para utilizar decoradores en un proyecto TypeScript, la opción experimentalDecorators debe estar habilitada en el archivo tsconfig.json.

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

Creando un decorador de clase

Los decoradores de clase se aplican al constructor de una clase. Son útiles para agregar metadatos o funcionalidad a la clase. A continuación, se muestra un ejemplo de cómo crear un decorador de clase simple.

function logClass(constructor: Function) {
  console.log(`Class ${constructor.name} is created`);
}

@logClass
class Person {
  constructor(public name: string) {}
}

const person = new Person("John");
// Output: Class Person is created

Creación de un decorador de métodos

Los decoradores de métodos se aplican a los métodos de clase. Se pueden utilizar para modificar u observar el comportamiento del método. A continuación, se muestra un ejemplo de un decorador de métodos que registra la ejecución del método.

function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Method ${propertyKey} is called with arguments:`, args);
    return originalMethod.apply(this, args);
  };

  return descriptor;
}

class Calculator {
  @logMethod
  add(a: number, b: number) {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3); 
// Output: Method add is called with arguments: [2, 3]

Creando un Decorador de Propiedades

Los decoradores de propiedades se pueden utilizar para observar o modificar propiedades. A continuación, se muestra un ejemplo en el que un decorador de propiedades garantiza que una propiedad tenga un valor predeterminado.

function defaultValue(value: any) {
  return function (target: any, propertyKey: string) {
    let propertyValue = value;

    const getter = function () {
      return propertyValue;
    };

    const setter = function (newValue: any) {
      propertyValue = newValue || value;
    };

    Object.defineProperty(target, propertyKey, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true,
    });
  };
}

class User {
  @defaultValue('Anonymous')
  name!: string;
}

const user = new User();
console.log(user.name); // Output: Anonymous
user.name = 'Alice';
console.log(user.name); // Output: Alice

Creación de un decorador de parámetros

Los decoradores de parámetros se aplican a los parámetros de un método. Pueden ser útiles para tareas como la validación o el registro de argumentos. A continuación, se muestra un ejemplo de un decorador de parámetros.

function logParameter(target: any, propertyKey: string, parameterIndex: number) {
  console.log(`Parameter at index ${parameterIndex} in method ${propertyKey} is being decorated`);
}

class Vehicle {
  drive(@logParameter speed: number) {
    console.log(`Driving at speed ${speed}`);
  }
}

const vehicle = new Vehicle();
vehicle.drive(50);
// Output: Parameter at index 0 in method drive is being decorated

Conclusión

Los decoradores en TypeScript ofrecen potentes capacidades de metaprogramación que pueden mejorar y ampliar la funcionalidad de clases, métodos y propiedades. Al utilizar decoradores personalizados, es posible crear estructuras de código reutilizables, eficientes y organizadas. Esta guía demostró la creación de diferentes tipos de decoradores: clase, método, propiedad y parámetro.