From d1434ae30f9b901ad1a48319ee0eb548ffbf7a38 Mon Sep 17 00:00:00 2001 From: streamich Date: Thu, 14 Mar 2024 10:12:10 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20"once"=20cla?= =?UTF-8?q?ss=20method=20decorator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/__tests__/once.spec.ts | 17 +++++++++++++++++ src/index.ts | 1 + src/once.ts | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 src/__tests__/once.spec.ts create mode 100644 src/once.ts diff --git a/src/__tests__/once.spec.ts b/src/__tests__/once.spec.ts new file mode 100644 index 0000000..c8ba3d4 --- /dev/null +++ b/src/__tests__/once.spec.ts @@ -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); +}); diff --git a/src/index.ts b/src/index.ts index 3370799..5f1dc7a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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'; diff --git a/src/once.ts b/src/once.ts new file mode 100644 index 0000000..62f2f72 --- /dev/null +++ b/src/once.ts @@ -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( + target: (this: This, ...args: Args) => Return, + context?: ClassMethodDecoratorContext 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; + }; +}