Reputation:
I have a method decorator that allows to execute a decorated method only once.This function works good,but at my third unit test it failes because it gives undefined but should return first execution result.
This is my decorator:
import "reflect-metadata";
const metadataKey = Symbol("initialized");
function once(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const method = descriptor.value;
descriptor.value = function (...args) {
const initialized = Reflect.getMetadata(
metadataKey,
target,
propertyKey
);
if (initialized) {
return;
}
Reflect.defineMetadata(metadataKey, true, target, propertyKey);
method.apply(this, args);
};
}
I think the problem is in the return from the if statement,it should return something but idk what.I played a little but got no succes,thats why i beg you for help.
These are the unit tests:
describe('once', () => {
it('should call method once with single argument', () => {
class Test {
data: string;
@once
setData(newData: string) {
this.data = newData;
}
}
const test = new Test();
test.setData('first string');
test.setData('second string');
assert.strictEqual(test.data, 'first string')
});
it('should call method once with multiple arguments', () => {
class Test {
user: {name: string, age: number};
@once
setUser(name: string, age: number) {
this.user = {name, age};
}
}
const test = new Test();
test.setUser('John',22);
test.setUser('Bill',34);
assert.deepStrictEqual(test.user, {name: 'John', age: 22})
});
it('should return always return first execution result', () => {
class Test {
@once
sayHello(name: string) {
return `Hello ${name}!`;
}
}
const test = new Test();
test.sayHello('John');
test.sayHello('Mark');
assert.strictEqual(test.sayHello('new name'), 'Hello John!')
})
});
Thanks in advance!
Upvotes: 1
Views: 173
Reputation: 9853
This decorator basically does memoization, but the result of the method call isn't stored anywhere. This is what's missing.
My suggestion would be to add another piece of metadata called result
or something:
const meta = Reflect.getMetadata(...);
if (meta?.initialized) return meta.result;
const result = method.apply(this, args);
const newMeta = { initialized: true, result };
Reflect.defineMetadata(metadataKey, newMeta, target, propertyKey);
Upvotes: 1