CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-moize

Blazing fast memoization library for JavaScript with comprehensive configuration options and React support

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

utility-methods.mddocs/

Utility Methods

Utility functions for working with memoized functions, composition, and type checking in the moize ecosystem.

Capabilities

Type Checking

Check if a value is a memoized function created by moize.

/**
 * Type guard to check if a value is a memoized function
 * @param value The value to test
 * @returns True if the value is a memoized function, false otherwise
 */
isMoized(value: any): value is Moized;

Usage Examples:

import moize from "moize";

const regularFunction = (x: number) => x * 2;
const memoizedFunction = moize(regularFunction);

// Type checking
console.log(moize.isMoized(regularFunction)); // false
console.log(moize.isMoized(memoizedFunction)); // true
console.log(moize.isMoized("not a function")); // false
console.log(moize.isMoized(null)); // false

// Use in conditional logic
function processFunction(fn: any) {
  if (moize.isMoized(fn)) {
    console.log('Working with memoized function');
    console.log('Cache size:', Array.from(fn.keys()).length);
    console.log('Original function name:', fn.originalFunction.name);
    
    // Access memoized function methods
    fn.clear();
    console.log('Cache cleared');
  } else if (typeof fn === 'function') {
    console.log('Working with regular function');
    console.log('Function name:', fn.name);
  } else {
    console.log('Not a function');
  }
}

processFunction(regularFunction);   // "Working with regular function"
processFunction(memoizedFunction);  // "Working with memoized function"

// Type-safe utility function
function getMemoizedFunctionStats(fn: unknown): { calls: number; hits: number } | null {
  if (moize.isMoized(fn)) {
    return fn.getStats();
  }
  return null;
}

const stats = getMemoizedFunctionStats(memoizedFunction);
console.log(stats); // { calls: 0, hits: 0 }

Function Composition

Compose multiple moizers to create complex memoization strategies.

/**
 * Compose multiple moizers into a single moizer
 * @param moizers The moizers or moize instances to compose
 * @returns A composed moizer that applies all configurations
 */
compose(...moizers: Array<Moize | Moizer>): Moizer;

Usage Examples:

import moize from "moize";

// Define individual moization strategies
const withCaching = moize.maxSize(50);
const withTTL = moize.maxAge(30000); // 30 seconds
const withProfiling = moize.profile('composed-functions');
const withDeepEquality = moize.deep;

// Compose strategies
const composedMemoizer = moize.compose(
  withCaching,
  withTTL,
  withProfiling,
  withDeepEquality
);

const expensiveOperation = (data: { items: any[]; config: any }) => {
  return data.items
    .filter(item => item.active)
    .map(item => ({ ...item, processed: true, timestamp: Date.now() }));
};

// Apply composed memoization
const memoizedOperation = composedMemoizer(expensiveOperation);

// The function now has all composed behaviors:
// - Max 50 cache entries
// - 30 second TTL
// - Profiled under 'composed-functions'
// - Uses deep equality for comparison

console.log(memoizedOperation.options);
// Contains all merged options from composed moizers

// Complex composition example
const apiMemoizer = moize.compose(
  moize.promise,              // Handle async functions
  moize.serialize,            // Serialize complex arguments
  moize.maxAge(60000),        // 1 minute TTL
  moize.maxSize(100),         // Up to 100 cached responses
  moize.profile('api-calls')  // Profile API performance
);

const fetchUserData = async (userId: string, includePreferences: boolean) => {
  const response = await fetch(`/api/users/${userId}?prefs=${includePreferences}`);
  return response.json();
};

const memoizedFetchUserData = apiMemoizer(fetchUserData);

// Database operation composition
const dbMemoizer = moize.compose(
  moize.promise,
  moize.deep,                    // Deep comparison for query objects
  moize.maxAge(120000),          // 2 minute TTL
  moize.transformArgs((key) => {  // Normalize query objects
    return key.map(arg => {
      if (arg && typeof arg === 'object' && 'query' in arg) {
        // Sort query keys for consistent caching
        const sortedQuery = Object.keys(arg.query)
          .sort()
          .reduce((result, key) => {
            result[key] = arg.query[key];
            return result;
          }, {} as any);
        return { ...arg, query: sortedQuery };
      }
      return arg;
    });
  }),
  moize.profile('database')
);

const queryDatabase = async (query: { table: string; where: any; limit?: number }) => {
  // Database query implementation
  return { results: [], count: 0 };
};

const memoizedDbQuery = dbMemoizer(queryDatabase);

Composition Order and Behavior

The order of composition matters for certain options, with later moizers taking precedence.

import moize from "moize";

const func = (x: number) => x * x;

// Order matters for conflicting options
const composed1 = moize.compose(
  moize.maxSize(10),    // This will be overridden
  moize.maxSize(20)     // This takes precedence
);

const composed2 = moize.compose(
  moize.maxSize(20),    // This will be overridden  
  moize.maxSize(10)     // This takes precedence
);

const memoized1 = composed1(func);
const memoized2 = composed2(func);

console.log(memoized1.options.maxSize); // 20
console.log(memoized2.options.maxSize); // 10

// Non-conflicting options are merged
const mergedComposition = moize.compose(
  moize.maxSize(15),
  moize.maxAge(5000),
  moize.deep,
  moize.profile('merged')
);

const mergedMemoized = mergedComposition(func);
console.log(mergedMemoized.options);
// {
//   maxSize: 15,
//   maxAge: 5000,  
//   isDeepEqual: true,
//   profileName: 'merged',
//   // ... other options
// }

Practical Composition Patterns

Common composition patterns for different use cases.

import moize from "moize";

// API call memoization pattern
const createApiMemoizer = (cacheDuration: number, cacheSize: number, profileName: string) => {
  return moize.compose(
    moize.promise,
    moize.serialize,
    moize.maxAge(cacheDuration, {
      updateExpire: true,  // Refresh TTL on cache hits
      onExpire: (key) => console.log(`API cache expired for:`, key)
    }),
    moize.maxSize(cacheSize),
    moize.profile(profileName)
  );
};

// Usage
const shortTermApiMemoizer = createApiMemoizer(30000, 50, 'short-api'); // 30s
const longTermApiMemoizer = createApiMemoizer(300000, 20, 'long-api');  // 5min

// Computation memoization pattern  
const createComputationMemoizer = (isHeavyComputation: boolean) => {
  const baseComposition = [
    moize.deep,  // Usually need deep equality for complex data
    moize.profile('computations')
  ];
  
  if (isHeavyComputation) {
    return moize.compose(
      ...baseComposition,
      moize.infinite,  // No size limit for expensive computations
      moize.transformArgs((key) => {
        // Normalize computation arguments
        return key.map(arg => {
          if (Array.isArray(arg)) {
            return [...arg].sort(); // Sort arrays for consistent caching
          }
          return arg;
        });
      })
    );
  } else {
    return moize.compose(
      ...baseComposition,
      moize.maxSize(100),
      moize.maxAge(60000) // 1 minute for lighter computations
    );
  }
};

// React component memoization pattern
const createReactMemoizer = (useDeepComparison: boolean = false) => {
  const composition = [moize.react, moize.maxSize(20)];
  
  if (useDeepComparison) {
    composition.push(moize.deep);
  } else {
    composition.push(moize.shallow);
  }
  
  return moize.compose(...composition);
};

// Development vs Production memoization
const createEnvironmentMemoizer = (isDevelopment: boolean) => {
  const baseComposition = [
    moize.maxSize(50),
    moize.maxAge(60000)
  ];
  
  if (isDevelopment) {
    // More verbose profiling and smaller cache in development
    return moize.compose(
      ...baseComposition,
      moize.profile('dev-functions'),
      moize.collectStats(true)
    );
  } else {
    // Optimized for production
    return moize.compose(
      ...baseComposition,
      moize.serialize  // Better cache key consistency in production
    );
  }
};

docs

argument-transformation.md

cache-introspection.md

cache-management.md

core-memoization.md

equality-comparison.md

index.md

specialized-memoization.md

statistics-profiling.md

utility-methods.md

tile.json