Search code examples
typescriptdecorator

Type-safe decorator for private method in Typescript


I tried to implement a decorator in typescript that can only be applied to async functions. If the decorator is applied to a none async function the compile should raise an error.

Here is what I tried so far:


type AsyncFunction = (...args: any[]) => Promise<any>

function MyDecorator(/* params as needed */) {
    return function <P extends string>(target: Record<P, AsyncFunction> , propertyKey: P) {
        console.log("Implementation of MyDecorator")
    }
}

class SomeClassWithPrivateMethod {

    @MyDecorator()
    private async somePrivateMethod() {

    }

    @MyDecorator()
    async somePublicMethod() {

    }

}

The problem is, that it does not work for private methods with the following error message:

Argument of type 'SomeClassWithPrivateMethod' is not assignable to parameter of type 'Record<"somePrivateMethod", AsyncFunction>'.   
Property 'somePrivateMethod' is private in type 'SomeClassWithPrivateMethod' but not in type 'Record<"somePrivateMethod", AsyncFunction>'.

What do I have to change to make it work for private methods?


Solution

  • For my use case I found a very simple solution
    - tested with typescript 4.6.3 -

    Instead of applying a contraint to the target parameter, it is possible restrict the descriptor parameter to a specific type:

    type AsyncFunction = (...args: any[]) => Promise<any>
    
    function MyDecorator(/* params as needed */) {
        return function(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<AsyncFunction>) {
            console.log("Implementation of MyDecorator")
        }
    }
    

    TypedPropertyDescriptor<AsyncFunction> is the key here. TypedPropertyDescriptor is a built in type from typescript.