# extra-memoize

> Yet another memoize library

Latest version **0.10.1** (published 2026-02-14) · MIT license · 0 weekly downloads

## Install

```sh
npm install extra-memoize
pnpm add extra-memoize
yarn add extra-memoize
bun add extra-memoize
```

## Health

**Score 60/100 (C)** — status: stable.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.10.1 |
| Published | 2026-02-14 |
| First published | 2021-05-18 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=22 |
| Dependencies | 2 |
| Unpacked size | 79.2 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 0 |
| Author | BlackGlory |
| Maintainers | black_glory |
| Keywords | memoize |

## Links

- npm: https://www.npmjs.com/package/extra-memoize
- Repository: https://github.com/extra-memoize/extra-memoize
- Homepage: https://github.com/extra-memoize/extra-memoize#readme
- Issues: https://github.com/extra-memoize/extra-memoize/issues
- npm.io page: https://npm.io/package/extra-memoize

## Dependencies (2)

- [@blackglory/prelude](https://npm.io/package/@blackglory/prelude.md) ^0.4.0
- [extra-json-stable-stringify](https://npm.io/package/extra-json-stable-stringify.md) ^0.1.2

## Recent versions

- 0.10.1 (latest) — 2026-02-14
- 0.10.0 — 2025-07-03
- 0.9.3 — 2023-06-10
- 0.9.2 — 2023-01-21
- 0.9.1 — 2022-09-12
- 0.9.0 — 2022-09-09
- 0.8.1 — 2022-09-09
- 0.8.0 — 2022-08-04
- 0.7.0 — 2022-06-26
- 0.6.0 — 2022-05-10
- 0.5.0 — 2022-04-08
- 0.4.9 — 2022-04-07
- 0.4.8 — 2022-04-06
- 0.4.7 — 2022-03-23
- 0.4.6 — 2022-01-06
- … 14 more at https://npm.io/package/extra-memoize/versions

## README

# extra-memoize
Yet another memoize library.

## Philosophy
Most memoize functions include strategies (such as TTL), which will actually cause poor cache performance, because memoize functions can only use common interfaces to implement related strategies.

`extra-memoize` takes another approach, its memoize function is very light. It delegates the implementation of the strategies to the cache layer and cache wrapper. This allows the cache backend to fully utilize their performance.

## Install
```sh
npm install --save extra-memoize
# or
yarn add extra-memoize
```

## Usage
```ts
import { memoize } from 'extra-memoize'
import { LRUCache } from '@extra-memoize/memory-cache'

const cache = new LRUCache(100)
const memoized = memoize({ cache }, fn)
```

## API
```ts
enum State {
  Miss = 'miss'
, Hit = 'hit'
, Reuse = 'reuse'
, StaleWhileRevalidate = 'stale-while-revalidate'
, StaleIfError = 'stale-if-error'
}

interface ICache<T> {
  set(key: string, value: T): void
  get(key: string): [State.Miss]
                  | [State.Hit, T]
}

interface IAsyncCache<T> {
  set(key: string, value: T): Promise<void>
  get(key: string): Promise<
                    | [State.Miss]
                    | [State.Hit, T]
                    >
}

interface IStaleWhileRevalidateCache<T> {
  set(key: string, value: T): void
  get(key: string): [State.Miss]
                  | [
                    | State.Hit
                    | State.StaleWhileRevalidate
                    , T
                    ]
}

interface IStaleWhileRevalidateAsyncCache<T> {
  set(key: string, value: T): Promise<void>
  get(key: string): Promise<
                    | [State.Miss]
                    | [
                      | State.Hit
                      | State.StaleWhileRevalidate
                      , T
                      ]
                    >
}

interface IStaleIfErrorCache<T> {
  set(key: string, value: T): void
  get(key: string): [State.Miss]
                  | [
                    | State.Hit
                    | State.StaleIfError
                    , T
                    ]
}

interface IStaleIfErrorAsyncCache<T> {
  set(key: string, value: T): Promise<void>
  get(key: string): Promise<
                    | [State.Miss]
                    | [
                      | State.Hit
                      | State.StaleIfError
                      , T
                      ]
                    >
}

interface IStaleWhileRevalidateAndStaleIfErrorCache<T> {
  set(key: string, value: T): void
  get(key: string): [State.Miss]
                  | [
                    | State.Hit
                    | State.StaleWhileRevalidate
                    | State.StaleIfError
                    , T
                    ]
}

interface IStaleWhileRevalidateAndStaleIfErrorAsyncCache<T> {
  set(key: string, value: T): Promise<void>
  get(key: string): Promise<
                    | [State.Miss]
                    | [
                      | State.Hit
                      | State.StaleWhileRevalidate
                      | State.StaleIfError
                      , T
                      ]
                    >
}
```

### memoize
```ts
type VerboseResult<T> = [T, State.Hit | State.Miss]

interface IMemoizeOptions<CacheValue, Args extends any[]> {
  cache: ICache<CacheValue>
  name?: string
  verbose?: boolean = false

  createKey?: (args: Args, name?: string) => string

  /**
   * Used to judge whether a function execution is too slow.
   * Only when the excution time of function is
   * greater than or equal to the value (in milliseconds),
   * the return value of the function will be cached.
   */
  executionTimeThreshold?: number = 0
}

function memoize<CacheValue, Result extends CacheValue, Args extends any[]>(
  options: IMemoizeOptions<CacheValue, Args> & { verbose: true }
, fn: (...args: Args) => Result
): (...args: Args) => VerboseResult<Result>
function memoize<CacheValue, Result extends CacheValue, Args extends any[]>(
  options: IMemoizeOptions<CacheValue, Args> & { verbose: false }
, fn: (...args: Args) => Result
): (...args: Args) => Result
function memoize<CacheValue, Result extends CacheValue, Args extends any[]>(
  options: Omit<IMemoizeOptions<CacheValue, Args>, 'verbose'>
, fn: (...args: Args) => Result
): (...args: Args) => Result
function memoize<CacheValue, Result extends CacheValue, Args extends any[]>(
  options: IMemoizeOptions<CacheValue, Args>
, fn: (...args: Args) => Result
): (...args: Args) => Result | VerboseResult<Result>
```

### memoizeAsync
```ts
type VerboseResult<T> = [T, State.Hit | State.Miss | State.Reuse]

interface IMemoizeAsyncOptions<CacheValue, Args extends any[]> {
  cache: ICache<CacheValue> | IAsyncCache<CacheValue>
  name?: string
  verbose?: boolean = false

  // The default is extra-json-stable-stringify([args, name])
  createKey?: (args: Args, name?: string) => string

  /**
   * Used to judge whether a function execution is too slow.
   * Only when the excution time of function is
   * greater than or equal to the value (in milliseconds),
   * the return value of the function will be cached.
   */
  executionTimeThreshold?: number
}

function memoizeAsync<CacheValue, Result extends CacheValue, Args extends any[]>(
  options: IMemoizeAsyncOptions<CacheValue, Args> & { verbose: true }
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<VerboseResult<Result>>
function memoizeAsync<CacheValue, Result extends CacheValue, Args extends any[]>(
  options: IMemoizeAsyncOptions<CacheValue, Args> & { verbose: false }
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result>
function memoizeAsync<CacheValue, Result extends CacheValue, Args extends any[]>(
  options: Omit<IMemoizeAsyncOptions<CacheValue, Args>, 'verbose'>
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result>
function memoizeAsync<CacheValue, Result extends CacheValue, Args extends any[]>(
  options: IMemoizeAsyncOptions<CacheValue, Args>
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result | VerboseResult<Result>>
```

### memoizeStaleWhileRevalidate
```ts
type VerboseResult<T> = [
  T
, State.Hit | State.Miss | State.Reuse | State.StaleWhileRevalidate
]

interface IMemoizeStalwWhileRevalidateOptions<
  CacheValue
, Args extends any[]
> {
  cache:
  | IStaleWhileRevalidateCache<CacheValue>
  | IStaleWhileRevalidateAsyncCache<CacheValue>
  name?: string
  verbose?: boolean = false

  // The default is extra-json-stable-stringify([args, name])
  createKey?: (args: Args, name?: string) => string

  /**
   * Used to judge whether a function execution is too slow.
   * Only when the excution time of function is
   * greater than or equal to the value (in milliseconds),
   * the return value of the function will be cached.
   */
  executionTimeThreshold?: number
}

function memoizeStaleWhileRevalidate<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStalwWhileRevalidateOptions<CacheValue, Args> & { verbose: true }
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<VerboseResult<Result>>
function memoizeStaleWhileRevalidate<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStalwWhileRevalidateOptions<CacheValue, Args> & { verbose: false }
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result>
function memoizeStaleWhileRevalidate<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: Omit<IMemoizeStalwWhileRevalidateOptions<CacheValue, Args>, 'verbose'>
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result>
function memoizeStaleWhileRevalidate<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStalwWhileRevalidateOptions<CacheValue, Args>
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result | VerboseResult<Result>>
```

### memoizeStaleIfError
```ts
type VerboseResult<T> = [T, State.Hit | State.Miss | State.StaleIfError]

interface IMemoizeStaleIfErrorOptions<CacheValue, Args extends any[]> {
  cache: IStaleIfErrorCache<CacheValue>
  name?: string
  verbose?: boolean = false

  // The default is extra-json-stable-stringify([args, name])
  createKey?: (args: Args, name?: string) => string

  /**
   * Used to judge whether a function execution is too slow.
   * Only when the excution time of function is
   * greater than or equal to the value (in milliseconds),
   * the return value of the function will be cached.
   */
  executionTimeThreshold?: number
}

function memoizeStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStaleIfErrorOptions<CacheValue, Args> & { verbose: true }
, fn: (...args: Args) => Result
): (...args: Args) => VerboseResult<Result>
function memoizeStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStaleIfErrorOptions<CacheValue, Args> & { verbose: false }
, fn: (...args: Args) => Result
): (...args: Args) => Result
function memoizeStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: Omit<IMemoizeStaleIfErrorOptions<CacheValue, Args>, 'verbose'>
, fn: (...args: Args) => Result
): (...args: Args) => Result
function memoizeStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStaleIfErrorOptions<CacheValue, Args>
, fn: (...args: Args) => Result
): (...args: Args) => Result | VerboseResult<Result>
```

### memoizeAsyncStaleIfError
```ts
type VerboseResult<T> = [
  T
, | State.Hit
  | State.Miss
  | State.Reuse
  | State.StaleIfError
]

interface IMemoizeStaleIfErrorOptions<CacheValue, Args extends any[]> {
  cache: IStaleIfErrorCache<CacheValue> | IStaleifErrorAsyncCache<CacheValue>
  name?: string
  verbose?: boolean = false

  // The default is extra-json-stable-stringify([args, name])
  createKey?: (args: Args, name?: string) => string

  /**
   * Used to judge whether a function execution is too slow.
   * Only when the excution time of function is
   * greater than or equal to the value (in milliseconds),
   * the return value of the function will be cached.
   */
  executionTimeThreshold?: number
}

function memoizeAsyncStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeAsyncStaleIfError<CacheValue, Args> & { verbose: true }
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<VerboseResult<Result>>
function memoizeAsyncStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeAsyncStaleIfError<CacheValue, Args> & { verbose: false }
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result>
function memoizeAsyncStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: Omit<IMemoizeAsyncStaleIfError<CacheValue, Args>, 'verbose'>
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result>
function memoizeAsyncStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeAsyncStaleIfError<CacheValue, Args>
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result | VerboseResult<Result>>
```

### memoizeStaleWhileRevalidateAndStaleIfError
```ts
type VerboseResult<T> = [
  T
, | State.Hit
  | State.Miss
  | State.Reuse
  | State.StaleWhileRevalidate
  | State.StaleIfError
]

interface IMemoizeStaleWhileRevalidateAndStaleIfError<
  CacheValue
, Args extends any[]
> {
  cache:
  | IStaleWhileRevalidateAndStaleIfErrorCache<CacheValue>
  | IStaleWhileRevalidateAndStaleIfErrorAsyncCache<CacheValue>
  name?: string
  verbose?: boolean = false

  // The default is extra-json-stable-stringify([args, name])
  createKey?: (args: Args, name?: string) => string

  /**
   * Used to judge whether a function execution is too slow.
   * Only when the excution time of function is
   * greater than or equal to the value (in milliseconds),
   * the return value of the function will be cached.
   */
  executionTimeThreshold?: number
}

function memoizeStaleWhileRevalidateAndStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStaleWhileRevalidateAndStaleIfError<CacheValue, Args>
         & { verbose: true }
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<VerboseResult<Result>>
function memoizeStaleWhileRevalidateAndStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStaleWhileRevalidateAndStaleIfError<CacheValue, Args>
         & { verbose: false }
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result>
function memoizeStaleWhileRevalidateAndStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: Omit<
    IMemoizeStaleWhileRevalidateAndStaleIfError<CacheValue, Args>
  , 'verbose'
  >
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result>
function memoizeStaleWhileRevalidateAndStaleIfError<
  CacheValue
, Result extends CacheValue
, Args extends any[]
>(
  options: IMemoizeStaleWhileRevalidateAndStaleIfError<CacheValue, Args>
, fn: (...args: Args) => Awaitable<Result>
): (...args: Args) => Promise<Result | VerboseResult<Result>>
```

---
_Source: https://npm.io/package/extra-memoize · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
