自动调用装饰函数

Automatically call decorated functions

目前,我的代码如下所示:

export class MyClass {
    public constructor() {
        this.doStuff1AtStartup();
        this.doStuff2AtStartup();
    }

    private doStuff1AtStartup(): void {
        // Do something here
    }

    private doStuff2AtStartup(): void {
        // Do something here
    }
}

但是,如果我需要添加更多函数并在构造函数中调用它们,这将变得非常乏味。因此,我尝试为我的函数创建装饰器,从构造函数中删除调用,而是在我的装饰器函数中调用该函数。

export class MyClass {
    @DecoratorWhichCallsMyClassAtStartup()
    private doStuffAtStartup() {
        // Do stuff here
    }
}

不过,我不知道如何保持上下文(使用 this.something 总是 returns 未定义)——我认为那是因为我现在正在从我的装饰器函数中调用该函数因此无法从那里获得对 class 实例的引用。我也曾尝试使用 bindapply 调用原始函数,但无法正常工作。

有人可以建议这种事情的实现吗?

documentation 的帮助下,我想出了这个:

function AutoCall(methods: string[]) {
    return function <T extends { new (...args: any[]): any }>(constructor: T) {
        return class extends constructor {
            constructor(...args: any[]) {
                super(...args);

                for (const method of methods) {
                    super[method]();
                }
            }
        }
    };
}

注意这一行:

If the class decorator returns a value, it will replace the class declaration with the provided constructor function.

这让我们可以为所欲为!我们可以将构造函数替换为自动为我们调用方法的构造函数。

这正是这个装饰器应该做的。不幸的是,我找不到一种方法让它接受它被调用的 class 的键,所以我不得不在这里使用 string[] 作为 methods.[=18= 的类型]

理想情况下,它还应该检查 super[method] 是否也是一个实际函数。

这里还有一个用法示例:

@AutoCall(["method"])
class MyClass {
    private method() {
        console.log("i was called");
    }
}

new MyClass(); // logs "i was called"

Playground