Los decoradores en TypeScript son una característica poderosa que permite modificar el comportamiento de clases, métodos, propiedades y parámetros. Los decoradores son una forma de metaprogramación que se puede utilizar para añadir anotaciones y una lógica predefinida a las estructuras de código.

¿Qué son los Decoradores?

Un decorador es una función especial que se puede aplicar a una clase, método, accesor, propiedad o parámetro. Los decoradores se definen con el símbolo @ seguido del nombre del decorador y se colocan justo antes de la declaración que desean modificar.

Tipos de Decoradores

  1. Decoradores de Clase: Se aplican a una clase.
  2. Decoradores de Método: Se aplican a un método de una clase.
  3. Decoradores de Accesor: Se aplican a un accesor (getter o setter) de una clase.
  4. Decoradores de Propiedad: Se aplican a una propiedad de una clase.
  5. Decoradores de Parámetro: Se aplican a un parámetro de un método de una clase.

Ejemplo Básico de Decorador de Clase

Vamos a empezar con un ejemplo simple de un decorador de clase. Este decorador añadirá una propiedad estática a la clase.

function addStaticProperty(constructor: Function) {
    constructor.prototype.staticProperty = "I am a static property";
}

@addStaticProperty
class MyClass {
    constructor() {
        console.log("MyClass instance created");
    }
}

const myInstance = new MyClass();
console.log((myInstance as any).staticProperty); // Output: I am a static property

Explicación

  1. Definición del Decorador: addStaticProperty es una función que toma el constructor de la clase como argumento y añade una propiedad estática a su prototipo.
  2. Aplicación del Decorador: El decorador @addStaticProperty se aplica a la clase MyClass.
  3. Uso de la Clase: Al crear una instancia de MyClass, podemos acceder a la propiedad estática añadida por el decorador.

Decoradores de Método

Los decoradores de método se utilizan para modificar el comportamiento de los métodos de una clase. Vamos a crear un decorador que loguea el tiempo de ejecución de un método.

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

    descriptor.value = function (...args: any[]) {
        const start = performance.now();
        const result = originalMethod.apply(this, args);
        const end = performance.now();
        console.log(`Execution time of ${propertyKey}: ${end - start}ms`);
        return result;
    };

    return descriptor;
}

class Example {
    @logExecutionTime
    compute() {
        // Simulate a time-consuming task
        for (let i = 0; i < 1e6; i++) {}
    }
}

const example = new Example();
example.compute(); // Output: Execution time of compute: Xms

Explicación

  1. Definición del Decorador: logExecutionTime es una función que toma el objeto objetivo (target), la clave de la propiedad (propertyKey) y el descriptor del método (descriptor).
  2. Modificación del Método: El decorador reemplaza el método original con una nueva función que mide el tiempo de ejecución y luego llama al método original.
  3. Aplicación del Decorador: El decorador @logExecutionTime se aplica al método compute de la clase Example.

Decoradores de Propiedad

Los decoradores de propiedad se utilizan para modificar las propiedades de una clase. Vamos a crear un decorador que convierte una propiedad en solo lectura.

function readonly(target: any, propertyKey: string) {
    Object.defineProperty(target, propertyKey, {
        writable: false
    });
}

class Person {
    @readonly
    name: string;

    constructor(name: string) {
        this.name = name;
    }
}

const person = new Person("John");
person.name = "Doe"; // Error: Cannot assign to read only property 'name'

Explicación

  1. Definición del Decorador: readonly es una función que toma el objeto objetivo (target) y la clave de la propiedad (propertyKey).
  2. Modificación de la Propiedad: El decorador utiliza Object.defineProperty para hacer que la propiedad sea de solo lectura.
  3. Aplicación del Decorador: El decorador @readonly se aplica a la propiedad name de la clase Person.

Ejercicio Práctico

Ejercicio

Crea un decorador de método llamado logArguments que registre los argumentos pasados a un método cada vez que se llame.

function logArguments(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    // Tu código aquí
}

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

const calculator = new Calculator();
calculator.add(2, 3); // Output: Arguments for add: [2, 3]

Solución

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

    descriptor.value = function (...args: any[]) {
        console.log(`Arguments for ${propertyKey}: ${JSON.stringify(args)}`);
        return originalMethod.apply(this, args);
    };

    return descriptor;
}

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

const calculator = new Calculator();
calculator.add(2, 3); // Output: Arguments for add: [2, 3]

Explicación

  1. Definición del Decorador: logArguments es una función que toma el objeto objetivo (target), la clave de la propiedad (propertyKey) y el descriptor del método (descriptor).
  2. Modificación del Método: El decorador reemplaza el método original con una nueva función que registra los argumentos y luego llama al método original.
  3. Aplicación del Decorador: El decorador @logArguments se aplica al método add de la clase Calculator.

Conclusión

Los decoradores en TypeScript son una herramienta poderosa para modificar y extender el comportamiento de clases, métodos, propiedades y parámetros. En esta sección, hemos cubierto los conceptos básicos de los decoradores y hemos visto ejemplos prácticos de cómo se pueden utilizar. Con esta base, estarás preparado para explorar y aplicar decoradores en tus propios proyectos.

En el siguiente módulo, profundizaremos en la programación asíncrona con TypeScript, comenzando con las promesas.

© Copyright 2024. Todos los derechos reservados