【问题标题】:Adding decorators to dynamically created functions in typescript将装饰器添加到打字稿中动态创建的函数
【发布时间】:2019-03-12 15:56:40
【问题描述】:

我正在打字稿中创建动态函数。在这些动态函数上,我想添加装饰器。实现这种情况的最佳方法是什么?有这种可能吗?

例如 - 想要实现这样的目标

@decorator1
@decorator2
var dynamicFunction = new Function('a', 'b', 'return a + b');
alert(dynamicFunction(2, 3));

另外,如果我要创建多个动态函数,如何在它们上添加装饰器?

例如。

var dynamicFunction:Array<Functions>; 
for (i=0; i<10; i++){
@decorator1
@decorator2
dynamicFunction[i] = new Function('a','b','return a+b');
}

【问题讨论】:

标签: javascript node.js typescript reflection decorator


【解决方案1】:

您不能将装饰器添加到直接函数中。来自 Typescript 文档 (https://www.typescriptlang.org/docs/handbook/decorators.html):

装饰器

装饰器是一种可以附加到类的特殊声明 声明、方法、访问器、属性或参数。装饰者使用表格 @expression,其中表达式必须计算为将在以下位置调用的函数 带有装饰声明信息的运行时。

当您尝试时,您会发现它不起作用,因为脚本编写的装饰器函数假定有一个类链接到正在装饰的内容,如文档中所述。

但是,我不推荐这样做,你可以在一个类中拥有你需要的功能,那么以下将适用:

方法装饰器

方法装饰器在方法之前声明 宣言。装饰器应用于属性描述符 方法,可用于观察、修改或替换方法 定义。不能在声明文件中使用方法装饰器, 在重载或任何其他环境上下文中(例如在声明中 类)。

方法装饰器的表达式将作为函数调用 在运行时,使用以下三个参数:

  1. 静态成员的类的构造函数,或者
  2. 实例成员的类的原型。成员的名称。
  3. 成员的属性描述符。

然后你可以像typescript Playground example那样做一些丑陋的黑客攻击

为方便起见,我也在此处提供代码。如果您检查 typescript Playground 或编译此代码,那么要做的一件好事是查看生成的 Javascript,它清楚地表明这不是为直接函数编写的。

function noisy() {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        alert(`I am decorating ${ propertyKey }`);
    };
}

class Test {
    @noisy()
    public testMethod() {
    }
}

class DynamicTest {
}


const testInstance = new Test();
testInstance.testMethod();


let dynamics = ["do", "something"];
for (let dynFunction of dynamics) {
    DynamicTest.prototype[dynFunction] = new Function(`alert("I am Dynamic ${dynFunction}")`);
    let decorator = noisy();
    decorator(DynamicTest.prototype, dynFunction, null);
}

const dynamicTestInstance = new DynamicTest();

dynamicTestInstance["do"]();
dynamicTestInstance["something"]();
function noisy() {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        alert(`I am decorating ${ propertyKey }`);
    };
}

class Test {
    @noisy()
    public testMethod() {
    }
}

class DynamicTest {
}


const testInstance = new Test();
testInstance.testMethod();


let dynamics = ["do", "something"];
for (let dynFunction of dynamics) {
    DynamicTest.prototype[dynFunction] = new Function(`alert("I am Dynamic ${dynFunction}")`);
    let decorator = noisy();
    decorator(DynamicTest.prototype, dynFunction, null);
}

const dynamicTestInstance = new DynamicTest();

dynamicTestInstance["do"]();
dynamicTestInstance["something"]();

在不了解您的具体问题的情况下,我无法想到需要以这种方式生成函数。也许是一个外部逻辑数据流,比如规则引擎?无论如何,这种动态生成很难测试和维护,因此请记住这一点,并在可能的情况下考虑其他方法。

【讨论】:

  • 感谢胡安的详细回答。我打算用这个来创建一个命令行工具应用程序,使用commander-ts npmjs.com/package/commander-ts。由于字数限制,无法添加完整代码。例如。 @command @command-option(--print) commandFunction(){ if (this.print){ console.log("hello");我将在这个应用程序中拥有至少 500 个命令。我不想为每个命令都输入条目,而是想从 JSON 文件中读取数据并动态创建命令结构,以便从终端识别和运行命令。
  • 那么为了实现上述应用程序的功能,您认为正确的方法是什么?谢谢
猜你喜欢
  • 2019-12-24
  • 2019-05-16
  • 1970-01-01
  • 2015-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
  • 2013-04-04
相关资源
最近更新 更多