TypeScript method decorator -- `this` with noImplicitThis enabled

Viewed 3757

I'm trying to write a simple method decorator, that does some simple logic before calling the original method. All the examples I could find boil down to calling originalMethod.apply(this, args) at the end -- but with noImplicitThis enabled in tsconfig.json, I get the following error:

[eval].ts(1,224): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.

I tried working around by calling originalMethod.apply(this as any, args), but the error persists.

Question: Are there any workarounds to call the original method, without disabling noImplicitThis for the whole project?


Minimal example -- works with noImplicitAny disabled:

function logBeforeCall1(): originalMethodDecorator {
    return function(
        target: any,
        propertyKey: string | symbol,
        descriptor: PropertyDescriptor,
    ): PropertyDescriptor {
        const originalMethod = descriptor.value;
        descriptor.value = (...args: any[]) => {
            console.log('hello!');
            return originalMethod.apply(this, args);
        };
        return descriptor;
    };
}

class Test1 {
    private num: number = 1;

    @logBeforeCall1()
    test(next: number): void {
        console.log(this.num, '->', next);
        this.num = next;
    }
}

  • I already know that decorators don't have access to a specific object instance (see e.g. this question), but using this in the above example works
  • Event the official docs on decorators use the construction from my example (see the Property Decorators section), so it works, but conflicts with noImplicitThis compiler option...
2 Answers

Thanks to @Grassator for inspiration -- this is a version that works. I don't believe this can be done type-safely in the current state of TypeScript though.

function logBeforeCall2(): originalMethodDecorator {
    return function(
        target: any,
        propertyKey: string | symbol,
        descriptor: PropertyDescriptor,
    ): PropertyDescriptor {
        const originalMethod = descriptor.value;
        descriptor.value = function(this: any, ...args: any[]): any {
            console.log('hello!');
            return originalMethod.apply(this, args);
        };
        return descriptor;
    };
}

...

> t2.test(5)
hello!
1 '->' 5

I do not think you can really get type safety, but if you just want to get rid of type error you can explicitly say that this: any (3rd line):

function logBeforeCall1() {
  return function (
    this: any,
    target: any,
    propertyKey: string | symbol,
    descriptor: PropertyDescriptor,
  ): PropertyDescriptor {
    const originalMethod = descriptor.value;
    descriptor.value = (...args: any[]) => {
      console.log('hello!');
      return originalMethod.apply(this, args);
    };
    return descriptor;
  };
}
Related