Skip to content

Instantly share code, notes, and snippets.

@max-lt
Created July 31, 2019 21:50
Show Gist options
  • Save max-lt/f4d4b30442c79d7d42a6241964da899c to your computer and use it in GitHub Desktop.
Save max-lt/f4d4b30442c79d7d42a6241964da899c to your computer and use it in GitHub Desktop.
Cache decorator typescript
import { Cache } from './cache.decorator';
class Test {
seed;
constructor(seed?) {
this.seed = seed || Math.random();
}
@Cache()
getValue(): number {
return this.seed;
}
@Cache()
getRandomValue(): number {
return Math.random();
}
@Cache()
mulRandomValue(mult = 3): number {
return mult * Math.random();
}
@Cache()
getNewInstance(): Test {
return new Test(Math.random());
}
}
describe('Cache decorator', () => {
const a = new Test(345);
const b = new Test();
it('Should correctly bind class reference (this)', () => {
expect(a.getValue()).toBeDefined();
expect(a.getValue()).toBe(345);
});
it('Should return the same vale twice if method called with no parameter', () => {
expect(a.getRandomValue()).toBe(a.getRandomValue());
expect(b.getRandomValue()).toBe(b.getRandomValue());
});
it('Should return different values if methods are not from the same instance', () => {
expect(a.getRandomValue()).not.toBe(b.getRandomValue());
});
it('Should cache a method called with no argument', () => {
expect(a.mulRandomValue()).toBe(a.mulRandomValue());
});
it('Should not cache a method called with argument', () => {
expect(a.mulRandomValue()).not.toBe(a.mulRandomValue(3));
expect(b.mulRandomValue(3)).not.toBe(b.mulRandomValue(3));
});
it('Should work with instances', () => {
expect(a.getNewInstance().seed).toBe(a.getNewInstance().seed);
});
});
export function Cache() {
return (target: any, name: string, desc: PropertyDescriptor) => {
// Keeping original method.
const fn = desc.value;
// Create a symbol for the targetted method.
const cache = Symbol(name + ' cache symbol');
// tslint:disable-next-line: only-arrow-functions
desc.value = function () {
if (!this[cache]) {
// Define this[cache]: this is our cache object.
Object.defineProperty(this, cache, { writable: true });
}
// We bypass cache if argument(s) provided.
if (arguments.length) {
return fn.apply(this, arguments);
}
// Set cache value if not defined
if (this[cache] === undefined) {
this[cache] = fn.apply(this);
}
return this[cache];
};
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment