Skip to content

Commit

Permalink
feat: 🎸 implement "once" class method decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Mar 14, 2024
1 parent 53b5efd commit d1434ae
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/__tests__/once.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {once} from '../once';

test('limits function invocation to one time only an memoizes the first result', async () => {
let executions = 0;
class A {
@once
test(value: number) {
executions++;
return value;
}
}
const a = new A();
expect(a.test(123)).toBe(123);
expect(a.test(1)).toBe(123);
expect(a.test(2)).toBe(123);
expect(executions).toBe(1);
});
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './base64';
export * from './Cache';
export * from './codeMutex';
export * from './concurrency';
export {once} from './once';
export {concurrency as concurrencyDecorator} from './concurrencyDecorator';
export * from './dataUri';
export * from './Defer';
Expand Down
18 changes: 18 additions & 0 deletions src/once.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* A class method decorator that limits a method to be called only once. All
* subsequent calls will return the result of the first call.
*/
export function once<This, Args extends any[], Return>(
target: (this: This, ...args: Args) => Return,
context?: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>,
) {
let called = false;
let res: unknown;
return function (this: This, ...args: Args): Return {
if (!called) {
called = true;
res = target.call(this, ...args);
}
return res as Return;
};
}

0 comments on commit d1434ae

Please sign in to comment.