TypeScript - 依赖间装饰器

时间:2018-04-03 12:59:45

标签: typescript

来自TypeScript docs

  

因此,在评估多个时执行以下步骤   TypeScript中单个声明的装饰器:

     
      
  1. 评估每个装饰器的表达式从上到下。在
  2.   然后将
  3. 结果称为从底部到顶部的函数。
  4.   

问题

我有两个装饰器,其中一个装饰器依赖另一个装饰器:

示例

@test()
@testCase({...})
public doSomething(): void {
}

@testCase()取决于@test(),因为在将测试用例添加到测试之前,需要将测试添加到测试运行器中。

我能做到......

@testCase({...})
@test()
public doSomething(): void {
}

但在声明某些内容是测试之前声明测试用例似乎很奇怪。

有没有办法让装饰者相互依赖,即testCase必须在test之后?

1 个答案:

答案 0 :(得分:2)

您可以在testcase中向目标函数添加额外信息,然后在test装饰器中检查额外信息。额外信息下面是更多装饰者可以参与的回调。这提供了很大的灵活性,但您可以添加其他信息而不是回调,并在test装饰器中使用该信息。

interface IAfterTestRegistered {
    afterTestRegisteredCallback?: ()=> void
}
// We could potentially have more then one contributor that need a callback executed.
function addCallback(obj: IAfterTestRegistered, callback : () => void) {
    let oldCallback = obj.afterTestRegisteredCallback;
    if(oldCallback != undefined) {
        obj.afterTestRegisteredCallback = () =>{
            oldCallback();
            callback();
        }
    }
    else{
        obj.afterTestRegisteredCallback = callback;
    }
}

function test() : MethodDecorator {
    return function<T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) : void {
        console.log("test");
        let targetFunction: IAfterTestRegistered = target[propertyKey];
        if(targetFunction.afterTestRegisteredCallback) {
            targetFunction.afterTestRegisteredCallback();
        }
    }
}

function testCase(data: { index: number}) : MethodDecorator {
    return function<T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) : void {
        console.log(`testcase ${data.index}`);
        addCallback(target[propertyKey], () =>
        {
            console.log(`after-register testcase ${data.index}`);
        });
    }
}

class myClass {
    @test()
    @testCase({ index: 1 })
    @testCase({ index: 2 })
    public doSomething(): void {
    }
}
// Will output
// testcase 2
// testcase 1
// test
// after-register testcase 2
// after-register testcase 1