From the TypeScript docs
As such, the following steps are performed when evaluating multiple decorators on a single declaration in TypeScript:
- The expressions for each decorator are evaluated top-to-bottom. The
- results are then called as functions from bottom-to-top.
Problem
I have two decorators where one decorator depends on another:
Example
@test()
@testCase({...})
public doSomething(): void {
}
@testCase() depends on @test() because the test need to be added to the test runner, before the test cases can be added to the test.
I could do...
@testCase({...})
@test()
public doSomething(): void {
}
but it seems odd to declare test cases before declaring that something is a test.
Is there any way to have decorators that depend on each other, i.e. a testCase must come after a test?
You can add extra information to the target function in testcase and then check for the extra information in the test decorator. Below the extra information is a callback to which more decorators can contribute to. This offers a lot of flexibility, but you could add other information instead of a callback and use that information in the test decorator.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With