Socket
Socket
Sign inDemoInstall

fast-typescript-memoize

Package Overview
Dependencies
1
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.4 to 1.1.0

.vscode/settings.json

50

dist/Memoize.d.ts
/**
* A @Memoize() decorator similar to
* https://www.npmjs.com/package/typescript-memoize. Differences:
* 1. If used to memoize async functions, it clears the memoize cache if the
* promise gets rejected (i.e. it doesn't memoize exceptions in async
* functions).
* 2. Stronger typing for internal code.
* Additional options for `@Memoize()` decorator.
*/
export declare function Memoize(hasher?: (...args: any[]) => unknown): (_target: object, _propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<any>) => void;
export interface MemoizeOptions {
/** Defaults to `true`. If true, rejected Promises returned from an async
* method will be removed from the cache as soon as the method finishes. */
clearOnReject?: boolean;
/** Defaults to `false`. If true, successfully resolved Promises returned from
* an async method will be removed from the cache as soon as the method
* finishes. This is a convenient mode for the cases when we want to coalesce
* multiple parallel executions of some method (e.g. when there is a burst of
* runs), but we don't want to prevent the method from further running. */
clearOnResolve?: boolean;
}
/**
* Remembers the returned value of a decorated method or getter in a hidden
* `this` object's property, so next time the method is called, the value will
* be returned immediately, without re-executing the method. This also works for
* async methods which return a Promise: in this case, multiple parallel calls
* to that method will coalesce into one call.
*
* All `@Memoize()` calls, for both methods and getters, accept a hasher
* function with the same list of arguments as the method itself (or, in case of
* a getter, with no arguments). The slot for the saved value will depend on the
* value returned by the hasher.
*/
export declare function Memoize<TThis, TValue>(hasher: TValue extends (...args: never[]) => unknown ? (this: TThis, ...args: Parameters<TValue>) => unknown : (this: TThis) => unknown, options?: MemoizeOptions): (target: TThis, propertyKey: string | symbol, descriptor: {
value?: TValue;
}) => void;
/**
* Remembers the returned value of a decorated method or getter in a hidden
* `this` object's property, so next time the method is called, the value will
* be returned immediately, without re-executing the method. This also works for
* async methods which return a Promise: in this case, multiple parallel calls
* to that method will coalesce into one call.
*
* Almost all `@Memoize()` calls may also omit the hasher function. Then, for
* 0-argument methods or getters, the slot for the saved value will be fixed.
* For 1-argument methods, the slot will be chosen based on that single
* argument's value. For methods with 2+ arguments, you must provide your own
* hasher function.
*/
export declare function Memoize<TThis, TValue>(options?: MemoizeOptions): (target: TThis, propertyKey: string | symbol, descriptor: {
value?: TValue;
}) => ((a1: unknown, a2: unknown, ...args: unknown[]) => never) extends TValue ? "provide-hasher-when-method-has-more-than-one-arg" : void;
//# sourceMappingURL=Memoize.d.ts.map

56

dist/Memoize.js

@@ -5,19 +5,16 @@ "use strict";

/**
* A @Memoize() decorator similar to
* https://www.npmjs.com/package/typescript-memoize. Differences:
* 1. If used to memoize async functions, it clears the memoize cache if the
* promise gets rejected (i.e. it doesn't memoize exceptions in async
* functions).
* 2. Stronger typing for internal code.
* A @Memoize() decorator implementation, inspired by:
* https://www.npmjs.com/package/typescript-memoize.
*/
function Memoize(hasher) {
function Memoize(a1, a2) {
const [hasher, options] = typeof a1 === "function" ? [a1, a2] : [undefined, a1];
return (_target, _propertyKey, descriptor) => {
if (descriptor.value !== null && descriptor.value !== undefined) {
descriptor.value = buildNewMethod(descriptor.value, hasher);
if (typeof descriptor.value === "function") {
descriptor.value = buildNewMethod(descriptor.value, hasher, options);
}
else if (descriptor.get) {
descriptor.get = buildNewMethod(descriptor.get, hasher);
descriptor.get = buildNewMethod(descriptor.get, hasher, options);
}
else {
throw "Only put a @Memoize() decorator on a method or get accessor.";
throw "Only put @Memoize() decorator on a method or get accessor.";
}

@@ -32,3 +29,6 @@ };

*/
function buildNewMethod(origMethod, hasher) {
function buildNewMethod(origMethod, hasher, { clearOnReject, clearOnResolve } = {
clearOnReject: true,
clearOnResolve: false,
}) {
const identifier = ++counter;

@@ -55,5 +55,8 @@ return function (...args) {

value = origMethod.apply(this, args);
if (value instanceof Promise) {
if (clearOnReject && value instanceof Promise) {
value = value.catch(deleteMapKeyAndRethrow.bind(undefined, map, hashKey));
}
if (clearOnResolve && value instanceof Promise) {
value = value.then(deleteMapKeyAndReturn.bind(undefined, map, hashKey));
}
map.set(hashKey, value);

@@ -69,7 +72,10 @@ }

value = origMethod.apply(this, args);
if (value instanceof Promise) {
value = value.catch(deleteObjKeyAndRethrow.bind(undefined, this, propValName));
if (clearOnReject && value instanceof Promise) {
value = value.catch(deleteObjPropAndRethrow.bind(undefined, this, propValName));
}
if (clearOnResolve && value instanceof Promise) {
value = value.then(deleteObjPropAndReturn.bind(undefined, this, propValName));
}
Object.defineProperty(this, propValName, {
configurable: true,
configurable: true, // to be able to remove it
enumerable: false,

@@ -96,6 +102,22 @@ writable: false,

*/
function deleteObjKeyAndRethrow(obj, key, e) {
function deleteObjPropAndRethrow(obj, key, e) {
delete obj[key];
throw e;
}
/**
* A helper function to just not use "=>" closures and thus control, which
* variables will be retained from garbage collection.
*/
function deleteMapKeyAndReturn(map, key, value) {
map.delete(key);
return value;
}
/**
* A helper function to just not use "=>" closures and thus control, which
* variables will be retained from garbage collection.
*/
function deleteObjPropAndReturn(obj, key, value) {
delete obj[key];
return value;
}
//# sourceMappingURL=Memoize.js.map
{
"name": "fast-typescript-memoize",
"version": "1.0.4",
"version": "1.1.0",
"description": "Fast memoization decorator and other helpers with 1st class support for Promises.",

@@ -31,15 +31,11 @@ "homepage": "https://github.com/dimikot/fast-typescript-memoize#readme",

},
"dependencies": {},
"dependencies": {
"typescript": "^5.0.4"
},
"devDependencies": {
"@types/jest": "^29.4.0",
"@types/lodash": "^4.13.1",
"@types/jest": "^29.5.12",
"delay": "^4.4.1",
"jest": "^29.5.0",
"lodash": "^4.13.1",
"ts-jest": "^29.0.5",
"typescript": "^4.9.5"
},
"peerDependencies": {
"lodash": "^4.13.1"
"jest": "^29.7.0",
"ts-jest": "^29.1.2"
}
}
# fast-typescript-memoize: fast memoization decorator and other helpers with 1st class support for Promises
## @Memoize() decorator
## `@Memoize()` decorator
A `@Memoize()` TypeScript decorator similar to
Remembers the returned value of a decorated method or getter in a hidden `this`
object's property, so next time the method is called, the value will be returned
immediately, without re-executing the method. This also works for async methods
which return a Promise: in this case, multiple parallel calls to that method
will coalesce into one call.
To work properly, requires TypeScript v5+.
The idea of `@Memoize()` decorator is brought from
[typescript-memoize](https://www.npmjs.com/package/typescript-memoize).
Differences:
1. If used to memoize async functions, it clears the memoize cache if the
promise gets rejected (i.e. it doesn't memoize exceptions in async
functions).
2. Stronger typing for internal code.
3. Does not support any notion of expiration.
1. If used to memoize async methods, by default (and when
`clearOnResolve=true`), it clears the memoize cache as soon as the Promise
gets rejected (i.e. it doesn't memoize exceptions in async methods). Parallel
async calls to the same method will still be coalesced into one call though
(until the Promise rejects).
2. A special mode is added, `clearOnResolve`. If `true`, successfully resolved
Promises returned from an async method will be removed from the cache as soon
as the method finishes. This is a convenient mode for the cases when we want
to coalesce multiple parallel executions of some method (e.g. when there is a
burst of runs), but we don't want to prevent the method from further running.
3. Strong typing for the optional hasher handler, including types of arguments
and even the type of `this`.
4. Does not support any notion of expiration.
```ts

@@ -22,2 +36,3 @@ import { Memoize } from "fast-typescript-memoize";

private count = 0;
private some = 42;

@@ -34,3 +49,3 @@ @Memoize()

@Memoize((arg1: string, arg2: number) => `${arg1}#${arg2}`)
@Memoize((arg1, arg2) => `${arg1}#${arg2}`)
method2(arg1: string, arg2: number) {

@@ -40,4 +55,9 @@ return count++;

@Memoize(function (arg1, arg2) { return `${this.some}:${arg1}#${arg2}`; })
method3(arg1: string, arg2: number) {
return count++;
}
@Memoize()
asyncMethod(arg: string) {
async asyncMethod(arg: string) {
count++;

@@ -48,5 +68,12 @@ if (arg == "ouch") {

}
@Memoize({ clearOnResolve: true })
async asyncCoalescingMethod(arg: string) {
await delay(100);
count++;
}
}
const obj = new Class();
obj.method0(); // count is incremented

@@ -62,2 +89,5 @@ obj.method0(); // count is NOT incremented

obj.method3("abc", 42); // count is incremented (strongly typed `this`)
obj.method3("abc", 42); // count is NOT incremented
await asyncMethod("ok"); // count is incremented

@@ -67,2 +97,10 @@ await asyncMethod("ok"); // count is NOT incremented

await asyncMethod("ouch"); // count is incremented, exception is thrown
await asyncCoalescingMethod("ok"); // count is incremented
await asyncCoalescingMethod("ok"); // count is incremented again
const [c1, c2] = await Promise.all([
asyncCoalescingMethod("ok"), // count is incremented
asyncCoalescingMethod("ok"), // not incremented! coalescing parallel calls
]);
assert(c1 === c2);
```

@@ -69,0 +107,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc