Blazing fast memoization library for JavaScript with comprehensive configuration options and React support
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Methods for customizing how arguments and cache keys are compared to determine cache hits, allowing fine-tuned control over memoization behavior.
Use deep equality checking for complex objects and nested data structures.
/**
* Deep equality memoization - compares objects and arrays by value recursively
* @returns Moizer with deep equality configuration
*/
deep: Moizer<{ isDeepEqual: true }>;Usage Examples:
import moize from "moize";
const processObject = (obj: { a: number; b: { c: string } }) => {
return `${obj.a}-${obj.b.c}`;
};
const memoizedProcess = moize.deep(processObject);
const obj1 = { a: 1, b: { c: "test" } };
const obj2 = { a: 1, b: { c: "test" } }; // Different object, same values
console.log(memoizedProcess(obj1)); // Computed
console.log(memoizedProcess(obj2)); // Cached (deep equality match)Use shallow equality checking for objects with only primitive properties.
/**
* Shallow equality memoization - compares object properties at the first level only
* @returns Moizer with shallow equality configuration
*/
shallow: Moizer<{ isShallowEqual: true }>;Usage Examples:
const processUser = (user: { id: number; name: string; active: boolean }) => {
return `User ${user.name} (${user.id}) - ${user.active ? 'active' : 'inactive'}`;
};
const memoizedProcessUser = moize.shallow(processUser);
const user1 = { id: 1, name: "Alice", active: true };
const user2 = { id: 1, name: "Alice", active: true }; // Different object, same properties
console.log(memoizedProcessUser(user1)); // Computed
console.log(memoizedProcessUser(user2)); // Cached (shallow equality match)Provide a custom function to determine if individual arguments are equal.
/**
* Custom argument equality matcher
* @param argMatcher Function to compare individual arguments
* @returns Moizer with custom argument matching
*/
matchesArg<Matcher extends IsEqual>(argMatcher: Matcher): Moizer<{ matchesArg: Matcher }>;
type IsEqual = (cacheKeyArg: any, keyArg: any) => boolean;Usage Examples:
// Case-insensitive string matching
const caseInsensitiveEquals = (a: any, b: any) => {
if (typeof a === 'string' && typeof b === 'string') {
return a.toLowerCase() === b.toLowerCase();
}
return a === b;
};
const formatName = (name: string) => name.trim().toUpperCase();
const memoizedFormatName = moize.matchesArg(caseInsensitiveEquals)(formatName);
console.log(memoizedFormatName("Alice")); // Computed
console.log(memoizedFormatName("ALICE")); // Cached (case-insensitive match)
console.log(memoizedFormatName("alice")); // Cached (case-insensitive match)
// Custom object comparison
const compareById = (a: any, b: any) => {
if (a && b && typeof a === 'object' && typeof b === 'object') {
return a.id === b.id;
}
return a === b;
};
const processUser = (user: { id: number; name: string }) => `User: ${user.name}`;
const memoizedProcessUser = moize.matchesArg(compareById)(processUser);
console.log(memoizedProcessUser({ id: 1, name: "Alice" })); // Computed
console.log(memoizedProcessUser({ id: 1, name: "Bob" })); // Cached (same id)Provide a custom function to determine if entire argument arrays (keys) are equal.
/**
* Custom key equality matcher
* @param keyMatcher Function to compare full argument arrays
* @returns Moizer with custom key matching
*/
matchesKey<Matcher extends IsMatchingKey>(keyMatcher: Matcher): Moizer<{ matchesKey: Matcher }>;
type IsMatchingKey = (cacheKey: Key, key: Key) => boolean;
type Key<Arg extends any = any> = Arg[];Usage Examples:
// Only compare first two arguments
const compareTwoArgs = (cacheKey: any[], key: any[]) => {
return cacheKey.length >= 2 && key.length >= 2 &&
cacheKey[0] === key[0] && cacheKey[1] === key[1];
};
const calculate = (a: number, b: number, metadata?: any) => a + b;
const memoizedCalculate = moize.matchesKey(compareTwoArgs)(calculate);
console.log(memoizedCalculate(1, 2, { debug: true })); // 3 (computed)
console.log(memoizedCalculate(1, 2, { debug: false })); // 3 (cached - metadata ignored)
console.log(memoizedCalculate(1, 3, { debug: true })); // 4 (computed - different b)
// Compare arguments in different order
const orderInsensitiveKey = (cacheKey: any[], key: any[]) => {
if (cacheKey.length !== key.length) return false;
const sortedCache = [...cacheKey].sort();
const sortedKey = [...key].sort();
return sortedCache.every((val, index) => val === sortedKey[index]);
};
const sum = (...numbers: number[]) => numbers.reduce((a, b) => a + b, 0);
const memoizedSum = moize.matchesKey(orderInsensitiveKey)(sum);
console.log(memoizedSum(1, 2, 3)); // 6 (computed)
console.log(memoizedSum(3, 1, 2)); // 6 (cached - same values, different order)Equality methods can be combined with other moize methods through chaining.
import moize from "moize";
const expensiveObjectOperation = (obj: { data: any[] }) => {
return obj.data.map(item => item.value).reduce((a, b) => a + b, 0);
};
// Deep equality with size limit and TTL
const memoized = moize.deep.maxSize(10).maxAge(5000)(expensiveObjectOperation);
// Custom equality with profiling
const customMemoized = moize
.matchesArg((a, b) => JSON.stringify(a) === JSON.stringify(b))
.profile('custom-equality')
.maxSize(20)(expensiveObjectOperation);Without explicit equality configuration, moize uses reference equality (===) for object comparison and SameValueZero for primitive values.
const processArray = (arr: number[]) => arr.reduce((a, b) => a + b, 0);
const memoized = moize(processArray);
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3]; // Different array instance
console.log(memoized(arr1)); // 6 (computed)
console.log(memoized(arr1)); // 6 (cached - same reference)
console.log(memoized(arr2)); // 6 (computed - different reference)