# Decoradores en TypeScript

Los decoradores nos permiten alterar dinámicamente la funcionalidad o añadir nuevas responsabilidades a un objeto a nivel de clase, propiedad, método o parámetro sin por ello tener que emplear otros mecanismos como la herencia.

Actualmente es una característica experimental y se encuentra en la etapa 2 como propuesta (opens new window) para JavaScript por parte de Ecma TC39 (opens new window), sin embargo ya es posible usarlo con la ayuda de Babel (opens new window).

# Decoradores de clase

El decorador de clase es una función que recibe la clase como parámetro y la devuelve después de hacer algo con ella.

const logClass = (target: any) => {
  console.log('logClass -> ', target);
  return target;
}

La sintaxis para aplicar el decorador a la clase es la que sigue:

@logClass
class User {
  private name: string;

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

  public getName() {
    return this.name;
  }
}

# Decoradores de método

El decorador de método es una función que recibe como parámetros la clase, el nombre del método y el descriptor de la propiedad del objeto (opens new window), el cual es un conjunto de información que define un comportamiento de propiedad. Este último parámetro se puede usar para observar, modificar o reemplazar la definición del método.

const logMethod = (target: Object, propertyKey: string, descriptor: PropertyDescriptor) => {
  console.log(`logMethod -> ${target}.${propertyKey}.${descriptor}`);
}

La sintaxis para aplicar el decorador al método es la que sigue:

class User {
  private name: string;

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

  }
  public getName(): string {
    return this.name;
  }

  @logMethod
  public synchronize(@logParam source: any): void {
    setTimeout(() => { console.log('User synchronized!'); }, 2000);
  }
}

# Decoradores de propiedades y parámetros

El decorador de propiedad es una función que recibe como parámetros la clase y el nombre de la propiedad.

El decorador de parámetro es una función que recibe como parámetros la clase, el nombre del parámetro y la posición del parámetro.

const logProperty = (target: Object, propertyKey: string) => {
  console.log(`logProperty -> ${target}.${propertyKey}`);
}

const logParam = (target: Object, propertyKey: string, parameterIndex: number) => {
  console.log(`logParam -> ${target}.${propertyKey}.${parameterIndex}`);
}

La sintaxis para aplicar el decorador a la propiedad y al parámetro es la que sigue:

class User {
  @logProperty
  private name: string;

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

  public getName(): string {
    return this.name;
  }

  public synchronize(@logParam source: any): void {
    setTimeout(() => { console.log('User synchronized!'); }, 2000);
  }
}

# Validación de clases con class-validator

Si estás buscando una librería que te facilite la validación de objetos utilizando decoradores en TypeScript, te recomiento el uso de class-validator (opens new window). Es una biblioteca sencilla de usar y que resuelve este problema de manera muy efectiva. Cuenta además con el aval del framework Nest (NestJS (opens new window)) que lo usa para dar soporte a su validación (opens new window) decorativa mediante esta potente librería. Aquí un pequeño ejemplo de su uso:

import {validate, Length, IsEmail} from 'class-validator';

export class User {
  @Length(2, 50)
  name: string;

  @IsEmail()
  email: string;
}

let user = new user();
user.name = 'Rafael';
user.email = 'email@email.com';

validate(user).then(errors => {
  if (errors.length > 0) {
    console.log('User is not valid. Errors: ', errors);
  } else {
    console.log('User is valid.');
  }
});