Saltar al contenido principal

Decoradores

Son una función normal

1. Implementar en tsconfig.json

En Nest lo hace automáticamente.

tsconfig.json
{
  "compilerOptions": {
    // -----------------------------------------------------------------------------
    "experimentalDecorators": true,
    // -----------------------------------------------------------------------------
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    /* Bundler mode */
    /* Linting */
  },
  "include": ["src"]
}

2. Definir decorator

Al usarse obtiene la referencia al target.

El target es la definición de la clase donde se usa el decorador; propiedades, constructor, métodos, etc.

Puede expandir, extender, añadir funcionalidades, bloquear funcionalidades, remover funcionalidades, sobreescribir la clase, etc.

const MiDecorador = () => {
  return (target: Function) => {
    //console.log(target);
    // puede retornar otra clase para soreescribir la principal
    return NewPokemon;
  };
};

// otra clase
class NewPokemon {
  constructor(public readonly id: number, public name: string) {}
  scream() {
    console.log(`${this.name.toUpperCase()}!!!`);
  }
  speak() {
    console.log(`${this.name}, ${this.name}!`);
  }
}

3. Implementar decorador

// 2. Usar decorador
@MiDecorador()
export class Pokemon {
  constructor(public readonly id: number, public name: string) {}

  scream() {
    console.log(`${this.name.toUpperCase()}!!!`);
  }

  speak() {
    console.log(`${this.name}, ${this.name}!`);
  }
}

export const charmander = new Pokemon(4, "Charmander");

Otro ejemplo

deprecated.decorator.ts
const Deprecated = (deprecationReason: string) => {
  return (
    target: any,
    memberName: string,
    propertyDescriptor: PropertyDescriptor
  ) => {
    // console.log({target})
    return {
      get() {
        const wrapperFn = (...args: any[]) => {
          console.warn(
            `Method ${memberName} is deprecated with reason: ${deprecationReason}`
          );
          //! Llamar la función propiamente con sus argumentos
          propertyDescriptor.value.apply(this, args);
        };
        return wrapperFn;
      },
    };
  };
};
export class Pokemon {
  constructor(public readonly id: number, public name: string) {}

  scream() {
    console.log(`${this.name.toUpperCase()}!!!`);
  }

  // usar decorador ----------------------------------------------------------------
  @Deprecated("Utilizar la version2 del metodo")
  speak() {
    console.log(`${this.name}, ${this.name}!`);
  }

  speak2() {
    console.log(`${this.name}, ${this.name}!`);
  }
}

// crear instancia y ver funcionamiento del decorador ------------------------------
export const charmander = new Pokemon(4, "Charmander");
// Al utilizar speack() se mostrará el mensaje de deprecación
charmander.speak();