CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-memoize-one

A memoization library which only remembers the latest invocation

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

Memoize One

Memoize One is a lightweight memoization library that implements a unique single-cache strategy, storing only the most recent function call result and arguments. Unlike traditional memoization libraries that maintain multiple cached entries with complex cache management, memoize-one simplifies memory usage by remembering only the latest invocation, automatically discarding previous results when new arguments are provided.

Package Information

  • Package Name: memoize-one
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install memoize-one

Core Imports

import memoizeOne from "memoize-one";
import type { EqualityFn, MemoizedFn } from "memoize-one";

For CommonJS:

const memoizeOne = require("memoize-one");

Basic Usage

import memoizeOne from "memoize-one";

// Simple function memoization
function add(a: number, b: number): number {
  return a + b;
}

const memoizedAdd = memoizeOne(add);

memoizedAdd(1, 2); // Function called, returns 3
memoizedAdd(1, 2); // Cache hit, returns 3 (function not called)
memoizedAdd(2, 3); // New arguments, function called, returns 5
memoizedAdd(1, 2); // Cache miss (not the latest), function called again

// Clear cache manually
memoizedAdd.clear();

Architecture

Memoize One uses a simple, memory-efficient architecture:

  • Single Cache Strategy: Only stores the most recent function call result, arguments, and context
  • Automatic Cache Invalidation: Previous results are automatically discarded when new arguments are provided
  • Context Sensitivity: Handles this context changes by invalidating the cache
  • Custom Equality: Supports custom argument comparison functions for complex data types
  • Type Safety: Full TypeScript support with generic function signature preservation

Capabilities

Memoization Function

Creates a memoized version of any function that remembers only the latest invocation result.

/**
 * Creates a memoized version of the provided function
 * @param resultFn - The function to be memoized
 * @param isEqual - Optional custom equality function for comparing arguments
 * @returns Memoized function with clear() method
 */
function memoizeOne<TFunc extends (this: any, ...newArgs: any[]) => any>(
  resultFn: TFunc,
  isEqual?: EqualityFn<TFunc>
): MemoizedFn<TFunc>;

Usage Examples:

import memoizeOne from "memoize-one";

// Basic memoization
const expensiveCalculation = (x: number, y: number) => {
  console.log("Computing...");
  return Math.pow(x, y);
};

const memoized = memoizeOne(expensiveCalculation);
memoized(2, 8); // Logs "Computing...", returns 256
memoized(2, 8); // No log, returns 256 from cache

// With custom equality function
import isDeepEqual from "lodash.isequal";

const processObjects = (data: any[]) => data.map(item => ({ ...item, processed: true }));
const memoizedProcess = memoizeOne(processObjects, isDeepEqual);

memoizedProcess([{ id: 1 }]); // Function called
memoizedProcess([{ id: 1 }]); // Cache hit with deep equality

Custom Equality Function

Defines how arguments are compared to determine cache hits.

/**
 * Function type for custom argument equality comparison
 * @param newArgs - New function arguments
 * @param lastArgs - Previously cached arguments
 * @returns True if arguments are considered equal (cache hit)
 */
type EqualityFn<TFunc extends (...args: any[]) => any> = (
  newArgs: Parameters<TFunc>,
  lastArgs: Parameters<TFunc>
) => boolean;

Usage Examples:

import memoizeOne, { EqualityFn } from "memoize-one";

// Shallow equality for array contents
const shallowArrayEqual: EqualityFn<(arr: number[]) => number> = (newArgs, lastArgs) => {
  const [newArr] = newArgs;
  const [lastArr] = lastArgs;
  return newArr.length === lastArr.length && 
         newArr.every((val, idx) => val === lastArr[idx]);
};

const sumArray = (arr: number[]) => arr.reduce((sum, val) => sum + val, 0);
const memoizedSum = memoizeOne(sumArray, shallowArrayEqual);

memoizedSum([1, 2, 3]); // Function called
memoizedSum([1, 2, 3]); // Cache hit (shallow equal)

Memoized Function Interface

The enhanced function returned by memoizeOne with additional cache management.

/**
 * Enhanced function interface with cache management
 */
type MemoizedFn<TFunc extends (this: any, ...args: any[]) => any> = {
  /** Clears the cached result and arguments */
  clear(): void;
  /** The original function signature with preserved context and types */
  (this: ThisParameterType<TFunc>, ...args: Parameters<TFunc>): ReturnType<TFunc>;
};

Usage Examples:

import memoizeOne from "memoize-one";

const fibonacci = (n: number): number => {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
};

const memoizedFib = memoizeOne(fibonacci);

memoizedFib(10); // Computed
memoizedFib(10); // From cache

// Clear cache when needed
memoizedFib.clear();
memoizedFib(10); // Computed again

// Works with context (this)
class Calculator {
  multiplier = 2;
  
  multiply = memoizeOne((value: number) => {
    return value * this.multiplier;
  });
}

const calc = new Calculator();
calc.multiply(5); // Returns 10
calc.multiply(5); // From cache

Default Equality Behavior

By default, memoize-one uses shallow equality comparison with special NaN handling:

  1. Argument Count: Arguments must have the same length
  2. Strict Equality: Each argument uses === comparison
  3. NaN Special Case: Two NaN values are considered equal (unlike normal ===)
  4. Context Sensitivity: Changes to this context automatically invalidate cache

Examples:

const memoized = memoizeOne((a, b) => a + b);

// Same arguments - cache hit
memoized(1, 2); // Computed
memoized(1, 2); // Cache hit

// Different argument count - cache miss
memoized(1, 2, 3); // Computed (different arg count)

// NaN handling
const memoizedNaN = memoizeOne((x) => x);
memoizedNaN(NaN); // Computed
memoizedNaN(NaN); // Cache hit (NaN === NaN in memoize-one)

// Object references
memoized({ id: 1 }, { id: 2 }); // Computed
memoized({ id: 1 }, { id: 2 }); // Cache miss (different object references)

Error Handling

When the memoized function throws an error, memoize-one handles it with specific behavior:

  1. Exception Propagation: If the memoized function throws, the memoized function also throws
  2. No Caching of Errors: Thrown results are never cached - each call with arguments that cause an exception will re-execute the function
  3. Cache Preservation: Previous successful cache results remain intact even when exceptions occur

Examples:

import memoizeOne from "memoize-one";

const canThrow = (shouldThrow: boolean, value: number) => {
  if (shouldThrow) {
    throw new Error("Something went wrong");
  }
  return value * 2;
};

const memoized = memoizeOne(canThrow);

// Successful call - result cached
const result1 = memoized(false, 5); // Returns 10, cached

// Exception call - no caching
try {
  memoized(true, 3); // Throws Error, not cached
} catch (e) {
  console.log("First error:", e.message);
}

// Same exception call - function called again (no cache)
try {
  memoized(true, 3); // Throws Error again, function re-executed
} catch (e) {
  console.log("Second error:", e.message);
}

// Previous successful result still cached
const result2 = memoized(false, 5); // Returns 10 from cache (not re-executed)
console.log(result1 === result2); // true

docs

index.md

tile.json