Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

143
Vistas
Properties are undefined within a decorator

I am trying to call a function that that has a decorator attached to it. What it does is run every x seconds which works just fine, however, when I try to log the properties in the function they output undefined, but in the constructor it displays the proper class.

If I call another function that is in the class, the function gets called, the issue just seems to be when accessing properties.

Here are a few of the ways I have tried to call the method:

export function Repeat(interval: number, delay: number = 0) {
  return (target: any, prop: any, descriptor: PropertyDescriptor) => {

    timer(delay * 1000, interval * 1000)
      .pipe(
        tap(i => descriptor.value.call(target, i)),
        tap(i => target[prop].call(target, i)),
        tap(i => target[prop].bind(target)(i))
      )
      .subscribe();

  };
}

Here is how I am implementing the decorator:

export class MyClass {

  constructor(private readonly v: Item) { 
    console.log(this.v); // outputs: typeof Item
  }

  @Repeat(1)
  repeat(count: number) {
    console.log(this.v); // outputs: undefined
    this.testFunc(); // runs the function
  }

  testFunc(){
    console.log('test function');
  }
}

Here is a stackblitz example

Edit

After playing for a bit, I can see that I can do this:

export function Repeat(interval: number, delay = 0) {
  return function (target: any, prop: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (this: GameObject, ...args: any[]) {
      const t = timer(delay * 1000, interval * 1000)
        .pipe(map<number, boolean>(i => originalMethod.apply(this, [i])))
        .subscribe();
    };
    return descriptor;
  };
}

Then when I call it in the class the repeater works:

export class MyClass {

  constructor(private readonly v: Item) { 
    this.repeat(0);
  }

  @Repeat(1)
  repeat(count: number) {
    console.log(this.v); // outputs: typeof Item
  }
}

However, this is not what I want to resort to, I would like the function to be called automatically and not manually.

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

So, to solve my issue I had to use a decorator at the class level along with at the method level. Then, in the constructor I run the method on the parent class.

First import the reflect-metadata module:

import 'reflect-metadata';
export function Component() {
  return <T extends { new (...args: any[]): any }>(target: T): any => {
    return class extends target {
      constructor(...args: any[]) {
        super(...args);
        const methods = Reflect.ownKeys(target.prototype) as string[];
        methods.forEach((method) => {
          // Get the saved metadata
          const r = Reflect.getMetadata('token', target.prototype, method);
          if (typeof r === 'function') {
            // Here is where we call the method.
            this[method]();
          }
        });
      }
    };
  };
}

Here is the repeat function:

export function Repeat(interval: number, delay = 0, times = Infinity) {
  return function (target: any, prop: string, descriptor: PropertyDescriptor) {
    // Define the metadata to be used for later
    Reflect.defineMetadata('token', target[prop], target, prop);
    const originalMethod = descriptor.value;
    descriptor.value = function (this: any, ...args: any[]) {
      timer(delay * 1000, interval * 1000)
        .pipe(map<number, boolean>((i) => originalMethod.apply(this, [i])))
        .subscribe();
    };
    return descriptor;
  };
}

Here is how it is implemented in the class:

@Component()
export class MyClass {

  constructor(private readonly v: Item) { 
    console.log(this.v); // outputs: typeof Item
  }

  @Repeat(1)
  repeat(count: number) {
    console.log(this.v); // outputs: typeof Item
  }
}

Here is the stackblitz example.

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda