# Technical Documentation: reduxjs/reselect

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/reduxjs/reselect)

### Overview (`README.md`)

# Reselect

[![npm package][npm-badge]][npm][![Coveralls][coveralls-badge]][coveralls][![GitHub Workflow Status][build-badge]][build]![TypeScript][typescript-badge]

A library for creating memoized "selector" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.

- Selectors can compute derived data, allowing [Redux] to store the minimal possible state.
- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.
- Selectors are composable. They can be used as input to other selectors.

The **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with [React-Redux].

## Installation

### Redux Toolkit

While Reselect is not exclusive to [Redux], it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.

```ts
import { createSelector } from '@reduxjs/toolkit'
```

### Standalone

For standalone usage, install the `reselect` package:

```bash
# NPM
npm install reselect

# Yarn
yarn add reselect

# pnpm
pnpm add reselect
```

---

## Documentation

The Reselect docs are available at **https://reselect.js.org**, and include usage guides and API references:

- [**Introduction**](https://reselect.js.org/introduction/getting-started)
- [**How Does Reselect Work?**](https://reselect.js.org/introduction/how-does-reselect-work)
- **API Reference**:
  - **[`createSelector`]**
  - **[`createSelectorCreator`]**
  - **[`createStructuredSelector`]**
  - [**Development-Only Checks**](https://reselect.js.org/api/development-only-checks)
  - **[`lruMemoize`]**
  - **[`weakMapMemoize`]**
- [**FAQ**](https://reselect.js.org/FAQ)

## Basic Usage

Reselect exports a [`createSelector`] API, which generates memoized selector functions. [`createSelector`] accepts one or more [input selectors], which extract values from arguments, and a [result function] function that receives the extracted values and should return a derived value. If the generated [output selector] is called multiple times, the output will only be recalculated when the extracted values have changed.

You can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/reselect-example-g3k9gf?file=/src/index.js):

```ts
import { createSelector } from 'reselect'

interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean }[]
}

const state: RootState = {
  todos: [
    { id: 0, completed: false },
    { id: 1, completed: true }
  ],
  alerts: [
    { id: 0, read: false },
    { id: 1, read: true }
  ]
}

const selectCompletedTodos = (state: RootState) => {
  console.log('selector ran')
  return state.todos.filter(todo => todo.completed === true)
}

selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran

const memoizedSelectCompletedTodos = createSelector(
  [(state: RootState) => state.todos],
  todos => {
    console.log('memoized selector ran')
    return todos.filter(todo => todo.completed === true)
  }
)

memoizedSelectCompletedTodos(state) // memoized selector ran
memoizedSelectCompletedTodos(state)
memoizedSelectCompletedTodos(state)

console.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false

console.log(
  memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)
) //=> true
```

As you can see from the example above, `memoizedSelectCompletedTodos` does not run the second or third time, but we still get the same return value as last time.

In addition to skipping unnecessary recalculations, `memoizedSelectCompletedTodos` returns the existing result reference if there is no recalculation. This is important for libraries like [React-Redux] or [React] that often rely on reference equality checks to optimize UI updates.

---

## Terminology

- <a name="selector-function"></a>[**Selector Function**](#selector-function): A function that accepts one or more JavaScript values as arguments, and derives a result. When used with [Redux], the first argument is typically the entire Redux store state.
- <a name="input-selectors"></a>[**input selectors**](#input-selectors): Basic selector functions used as building blocks for creating a memoized selector. They are passed as the first argument(s) to [`createSelector`], and are called with all selector arguments. They are responsible for extracting and providing necessary values to the [result function].
- <a name="output-selector"></a>[**Output Selector**](#output-selector): The actual memoized selectors created by [`createSelector`].
- <a name="result-function"></a>[**Result Function**](#result-function): The function that comes after the [input selectors]. It takes the [input selectors]' return values as arguments and returns a result.
- <a name="dependencies"></a>[**`Dependencies`**](#dependencies): Same as [input selectors]. They are what the [output selector] "depends" on.

The below example serves as a visual aid:

```ts
const outputSelector = createSelector(
  [inputSelector1, inputSelector2, inputSelector3], // synonymous with `dependencies`.
  resultFunc // Result function
)
```

---

## What's New in 5.0.0?

Version 5.0.0 introduces several new features and improvements:

- **Customization Enhancements**:

  - Added the ability to pass an options object to [`createSelectorCreator`], allowing for customized `memoize` and `argsMemoize` functions, alongside their respective options (`memoizeOptions` and `argsMemoizeOptions`).
  - The [`createSelector`] function now supports direct customization of `memoize` and `argsMemoize` within its options object.

- **Memoization Functions**:

  - Introduced a new default memoization function: `weakMapMemoize`
  - Incorporated `memoize` and `argsMemoize` into the [output selector fields] for debugging purposes.

- **TypeScript Support and Performance**:

  - Discontinued support for TypeScript versions below 4.7, aligning with modern TypeScript features.
  - Significantly improved TypeScript performance for nesting [output selectors][output selector]. The nesting limit has increased from approximately 8 to around 30 [output selectors][output selector], greatly reducing the occurrence of the infamous `Type instantiation is excessively deep and possibly infinite` error.

- **Selector API Enhancements**:

  - Removed the second overload of `createStructuredSelector` due to its susceptibility to runtime errors.

- **Additional Functionalities**:

  - Added `dependencyRecomputations` and `resetDependencyRecomputations` to the [output selector fields]. These additions provide greater control and insight over [input selectors], complementing the new `argsMemoize` API.
  - Introduced `inputStabilityCheck`, a development tool that runs the [input selectors] twice using the same arguments and triggers a warning If they return differing results for the same call.
  - Introduced `identityFunctionCheck`, a development tool that checks to see if the [result function] returns its own input.

These updates aim to enhance flexibility, performance, and developer experience. For detailed usage and examples, refer to the updated documentation sections for each feature.

- **Breaking Changes**:

  - Removed `ParametricSelector` and `OutputParametricSelector` types. Their functionalities are now integrated into `Selector` and `OutputSelector` respectively, which inherently support additional parameters.

<div align="right">[ <a href="installation">↑ Back to top ↑</a> ]</div>

---

## License

MIT

## References

<details><summary><b>Click to Expand</b></summary>

Originally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).

[typescript-badge]: https://img.shields.io/badge/TypeScript-v4%2E7%2B-007ACC?style=for-the-badge&logo=TypeScript&logoColor=black&labelColor=blue&color=gray
[build-badge]: https://img.shields.io/github/actions/workflow/status/reduxjs/reselect/build-and-test-types.yml?branch=master&style=for-the-badge
[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml
[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=for-the-badge
[npm]: https://www.npmjs.org/package/reselect
[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=for-the-badge
[coveralls]: https://coveralls.io/github/reduxjs/reselect



[Redux]: https://redux.js.org 'Redux'
[React]: https://react.dev 'React'
[React-Redux]: https://react-redux.js.org 'React-Redux'



[selector]: #selector-function 'Selector Function'
[input selectors]: #input-selectors 'Input Selectors'
[output selector]: #output-selector 'Output Selector'
[result function]: #result-function 'Result Function'
[output selector fields]: https://reselect.js.org/api/createSelector#output-selector-fields 'Output Selector Fields'
[`createSelector`]: https://reselect.js.org/api/createSelector 'createSelector'
[`createSelectorCreator`]: https://reselect.js.org/api/createSelectorCreator 'createSelectorCreator'
[`lruMemoize`]: https://reselect.js.org/api/lruMemoize 'lruMemoize'
[`weakMapMemoize`]: https://reselect.js.org/api/weakMapMemoize 'weakMapMemoize'
[`createStructuredSelector`]: https://reselect.js.org/api/createStructuredSelector 'createStructuredSelector'

</details>

---

### Overview (`docs/README.md`)

# Reselect docs

The pages in this folder are published as part of the combined Redux docs site, at https://redux.js.org/reselect. The site itself (Docusaurus config, theme, search, redirects, build scripts) lives in the [`reduxjs/redux`](https://github.com/reduxjs/redux) repo under `website/`. This folder holds only the Reselect pages.

## What lives where

| What                                                                 | Where                                       |
| -------------------------------------------------------------------- | ------------------------------------------- |
| Reselect pages                                                       | `docs/**/*.{md,mdx}` in this repo           |
| Reselect sidebar                                                     | `docs/sidebars.ts` in this repo             |
| Code examples shown in the pages                                     | `docs/examples/` in this repo               |
| Images used by these pages                                           | `docs/assets/`, referenced by relative path |
| Tutorials, TypeScript setup, style guide, FAQ, troubleshooting       | `docs/` in `reduxjs/redux`                  |
| Site config, navbar, theme, search, redirects (`website/_redirects`) | `website/` in `reduxjs/redux`               |

Topics shared by all the Redux libraries are written once, in the core docs. Deriving data with selectors is covered in the core usage guide at `/usage/deriving-data-selectors`. Link to those pages instead of repeating them here.

## Links

- Other Reselect pages: a relative file link (`../api/createSelector.mdx`) or a site path (`/reselect/api/createSelector`).
- Other libraries and the core docs: site paths, such as `/usage/deriving-data-selectors`, `/toolkit/api/createSelector`, or `/react-redux/api/hooks`. Do not use full `https://redux.js.org/...` URLs.
- When you rename, move, or delete a page, add a redirect for the old URL to `website/_redirects` in `reduxjs/redux`.

## Sidebar

New pages only appear in the navigation once they are listed in `docs/sidebars.ts`. The file has no imports because the site loads it from a copy of this folder. Its local `SidebarItem` type catches misspelled keys:

```bash
pnpm exec tsc -p docs/tsconfig.json --noEmit
```

The site build checks that every doc id in the sidebar exists.

## Code examples

The TypeScript/JavaScript tabs in the pages are generated from the files in `docs/examples/`, which are type-checked against `src/`. To add or change one:

1. Edit or add the file under `docs/examples/`.
2. In the page, add a `{/* START: path/to/example.ts */}` line and a matching `{/* END: path/to/example.ts */}` line where the tabs should go. The path is relative to `docs/examples/`.
3. Run `pnpm docs:examples`. It compiles the examples to JavaScript, writes both versions into the pages between the markers, and formats the result.
4. Commit the updated pages. The site does not run this script; it publishes the pages as committed.

## Previewing a PR

Every PR that changes `docs/` gets a Netlify deploy preview of the whole combined site, with this branch's Reselect docs in place of the published ones.

## Previewing locally

Clone `reduxjs/redux` next to this repo and install the site's dependencies once:

```bash
git clone https://github.com/reduxjs/redux.git ../redux
cd ../redux/docs && pnpm install
cd ../website && pnpm install
```

Then start the dev server from `../redux/website`, pointing it at this checkout:

```bash
DOCS_SOURCE_RESELECT=../../reselect pnpm dev
```

`pnpm dev` copies this repo's docs into `website/external/reselect`, copies each file again when it changes, and runs `docusaurus start`. The other libraries are cloned from GitHub. Set `DOCS_SOURCE_REDUX_TOOLKIT` or `DOCS_SOURCE_REACT_REDUX` as well to use local checkouts of those.

The dev server does not report broken links. To run the same checks as a deploy preview:

```bash
DOCS_SOURCE_RESELECT=../../reselect pnpm fetch-docs --force
pnpm build
```

---

### Introduction Getting Started (`docs/introduction/getting-started.mdx`)

---
id: getting-started
title: Getting Started
sidebar_label: Getting Started
sidebar_position: 1
hide_title: true
description: 'Getting Started'
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import Link from '@docusaurus/Link'

# Getting Started with Reselect

A library for creating memoized "selector" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.

- Selectors can compute derived data, allowing [Redux](/) to store the minimal possible state.
- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.
- Selectors are composable. They can be used as input to other selectors.

If you are using Reselect in a Redux app, start with the **Redux docs usage page on [Deriving Data with Selectors](/usage/deriving-data-selectors)**. It covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with [React-Redux](/react-redux/). These Reselect docs are the reference for the library itself: how the memoization works, the full API, and the FAQ.

## Installation

### Redux Toolkit

While Reselect is not exclusive to [Redux](/), it is already included by default in [the official Redux Toolkit package](/toolkit/) - no further installation needed.

```ts
import { createSelector } from '@reduxjs/toolkit'
```

### Standalone

For standalone usage, install the `reselect` package:

```bash
npm install reselect
```

---

## Basic Usage

Reselect exports a `createSelector` API, which generates memoized selector functions. `createSelector` accepts one or more input selectors, which extract values from arguments, and a result function that receives the extracted values and should return a derived value. If the generated output selector is called multiple times, the output will only be recalculated when the extracted values have changed.

You can play around with the following **example** in <Link to='https://codesandbox.io/s/reselect-example-g3k9gf?file=/src/index.js'>this CodeSandbox</Link>:

{/* START: basicUsage.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="basicUsage.ts"
import { createSelector } from 'reselect'

interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean }[]
}

const state: RootState = {
  todos: [
    { id: 0, completed: false },
    { id: 1, completed: true }
  ],
  alerts: [
    { id: 0, read: false },
    { id: 1, read: true }
  ]
}

const selectCompletedTodos = (state: RootState) => {
  console.log('selector ran')
  return state.todos.filter(todo => todo.completed === true)
}

selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran

const memoizedSelectCompletedTodos = createSelector(
  [(state: RootState) => state.todos],
  todos => {
    console.log('memoized selector ran')
    return todos.filter(todo => todo.completed === true)
  }
)

memoizedSelectCompletedTodos(state) // memoized selector ran
memoizedSelectCompletedTodos(state)
memoizedSelectCompletedTodos(state)

console.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false

console.log(
  memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)
) //=> true
```

  </TabItem>
  <TabItem value='js'>

```js title="basicUsage.js"
import { createSelector } from 'reselect'

const state = {
  todos: [
    { id: 0, completed: false },
    { id: 1, completed: true }
  ],
  alerts: [
    { id: 0, read: false },
    { id: 1, read: true }
  ]
}

const selectCompletedTodos = state => {
  console.log('selector ran')
  return state.todos.filter(todo => todo.completed === true)
}

selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran

const memoizedSelectCompletedTodos = createSelector(
  [state => state.todos],
  todos => {
    console.log('memoized selector ran')
    return todos.filter(todo => todo.completed === true)
  }
)

memoizedSelectCompletedTodos(state) // memoized selector ran
memoizedSelectCompletedTodos(state)
memoizedSelectCompletedTodos(state)

console.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false

console.log(
  memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)
) //=> true
```

  </TabItem>
</Tabs>

{/* END: basicUsage.ts */}

As you can see from the example above, `memoizedSelectCompletedTodos` does not run the second or third time, but we still get the same return value as last time.

In addition to skipping unnecessary recalculations, `memoizedSelectCompletedTodos` returns the existing result reference if there is no recalculation. This is important for libraries like React-Redux or React that often rely on reference equality checks to optimize UI updates.

---

## Terminology

### Selector Function

A function that accepts one or more JavaScript values as arguments, and derives a result. When used with Redux, the first argument is typically the entire Redux store state.

### Input Selectors

Basic selector functions used as building blocks for creating a memoized selector. They are passed as the first argument(s) to [`createSelector`](../api/createSelector.mdx), and are called with all selector arguments. They are responsible for extracting and providing necessary values to the [result function](#result-function).

### Output Selector

The actual memoized selector created by `createSelector`.

### Result Function

The function that comes after the input selectors. It takes the input selectors' return values as arguments and returns a result.

### Dependencies

Same as input selectors. They are what the output selector "depends" on.

The below example serves as a visual aid:

```ts
const outputSelector = createSelector(
  [inputSelector1, inputSelector2, inputSelector3], // synonymous with `dependencies`.
  resultFunc // Result function
)
```

---

### FAQ (`docs/FAQ.mdx`)

---
id: FAQ
title: FAQ
sidebar_label: FAQ
hide_title: true
description: FAQ
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import Link from '@docusaurus/Link'

# FAQ

## Why isn’t my selector recomputing when the input state changes?

Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using [Redux](/)). For example, a selector created with [`createSelector`](./api/createSelector.mdx) will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](/usage/troubleshooting).

## Why is my selector recomputing when the input state stays the same?

To address unexpected recomputations in your selector, first ensure that `inputStabilityCheck` is set to either `'always'` or `'once'`. This setting aids in debugging by monitoring the stability of your inputs. Additionally, utilize [output selector fields](./api/createSelector.mdx#output-selector-fields) such as `recomputations`, `resetRecomputations`, `dependencyRecomputations`, and `resetDependencyRecomputations`. These tools help identify the source of the issue.

Keep an eye on the `dependencyRecomputations` count. If it increases while `recomputations` remains the same, it suggests that your arguments are changing references but your [input selectors](./introduction/getting-started.mdx#input-selectors) are stable which is typically the desired behavior.

To delve deeper, you can determine which arguments are changing references too frequently by using the `argsMemoizeOptions` and `equalityCheck`. Consider the following example:

{/* START: FAQ/selectorRecomputing.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="FAQ/selectorRecomputing.ts"
import { createSelector, lruMemoize } from 'reselect'

export interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean; type: string }[]
}

const selectAlertsByType = createSelector(
  [
    (state: RootState) => state.alerts,
    (state: RootState, type: string) => type
  ],
  (alerts, type) => alerts.filter(todo => todo.type === type),
  {
    argsMemoize: lruMemoize,
    argsMemoizeOptions: {
      // This will check the arguments passed to the output selector.
      equalityCheck: (a, b) => {
        if (a !== b) {
          console.log('Changed argument:', a, 'to', b)
        }
        return a === b
      }
    }
  }
)
```

  </TabItem>
  <TabItem value='js'>

```js title="FAQ/selectorRecomputing.js"
import { createSelector, lruMemoize } from 'reselect'

const selectAlertsByType = createSelector(
  [state => state.alerts, (state, type) => type],
  (alerts, type) => alerts.filter(todo => todo.type === type),
  {
    argsMemoize: lruMemoize,
    argsMemoizeOptions: {
      // This will check the arguments passed to the output selector.
      equalityCheck: (a, b) => {
        if (a !== b) {
          console.log('Changed argument:', a, 'to', b)
        }
        return a === b
      }
    }
  }
)
```

  </TabItem>
</Tabs>

{/* END: FAQ/selectorRecomputing.ts */}

## Can I use Reselect without Redux?

Yes. Reselect has no dependencies on any other package, so although it was designed to be used with [Redux](/) it can be used independently. It can be used with any plain JS data, such as typical [React](https://react.dev) state values, as long as that data is being updated immutably.

## How do I create a selector that takes an argument?

Each of the [input selectors](./introduction/getting-started.mdx#input-selectors) you provide will be called with all of the selector's arguments. You can add additional input selectors to extract arguments and forward them to the [result function](./introduction/getting-started.mdx#result-function), like this:

```ts
const selectTodosByCategory = createSelector(
  (state: RootState) => state.todos,
  // Extract the second argument to pass it on
  (state: RootState, category: string) => category,
  (todos, category) => todos.filter(t => t.category === category)
)
```

When creating a selector that accepts arguments in Reselect, it's important to structure your input and [output selectors](./introduction/getting-started.mdx#output-selector) appropriately. Here are key points to consider:

1. **Consistency in Arguments**: Ensure that all positional arguments across input selectors are of the same type for consistency.

2. **Selective Argument Usage**: Design each selector to use only its relevant argument(s) and ignore the rest. This is crucial because all input selectors receive the same arguments that are passed to the output selector.

Suppose we have the following state structure:

```ts
interface RootState {
  items: {
    id: number
    category: string
    vendor: { id: number; name: string }
  }[]
  // ... other state properties ...
}
```

To create a selector that filters `items` based on a `category` and excludes a specific `id`, you can set up your selectors as follows:

```ts
const selectAvailableItems = createSelector(
  [
    // First input selector extracts items from the state
    (state: RootState) => state.items,
    // Second input selector forwards the category argument
    (state: RootState, category: string) => category,
    // Third input selector forwards the ID argument
    (state: RootState, category: string, id: number) => id
  ],
  // Output selector uses the extracted items, category, and ID
  (items, category, id) =>
    items.filter(item => item.category === category && item.id !== id)
)
```

Internally Reselect is doing this:

```ts
// Input selector #1
const items = (state: RootState, category: string, id: number) => state.items
// Input selector #2
const category = (state: RootState, category: string, id: number) => category
// Input selector #3
const id = (state: RootState, category: string, id: number) => id
// result of output selector
const finalResult =
  // The result function
  items.filter(item => item.category === category && item.id !== id)
```

In this example, `selectItemId` expects that its second argument will be some simple value, while `selectVendorName` expects that the second argument is an object. If you call `selectItemById(state, 42)`, `selectVendorName` will break because it's trying to access `42.name`. Reselect's TS types should detect this and prevent compilation:

```ts
const selectItems = (state: RootState) => state.items

// expects a number as the second argument
const selectItemId = (state: RootState, itemId: number) => itemId

// expects an object as the second argument
const selectVendorName = (
  state: RootState,
  vendor: { id: number; name: string }
) => vendor.name

const selectItemById = createSelector(
  [selectItems, selectItemId, selectVendorName],
  (items, itemId, vendorName) => items[itemId]
)
```

## Can the memoization behavior be customized?

Yes. The built-in `lruMemoize` memoizer works great for a lot of use cases, but it can be customized or swapped out for a different memoizer. See [these examples](./api/createSelectorCreator.mdx#customize-equalitycheck-for-lrumemoize).

## How do I test a selector?

Selectors are pure functions - for a given input, a selector should always produce the same result. For this reason they are simple to unit test: call the selector with a set of inputs, and assert that the result value matches an expected shape.

{/* START: FAQ/howToTest.test.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```
/* Detailed source-code truncated for AI context efficiency. */
```

  </TabItem>
  <TabItem value='js'>

```
/* Detailed source-code truncated for AI context efficiency. */
```

  </TabItem>
</Tabs>

{/* END: FAQ/howToTest.test.ts */}

:::note Resetting a selector's cache between tests

Because Reselect uses a [two-stage "cascading" memoization](./introduction/how-does-reselect-work.mdx#cascading-memoization), a memoized selector holds _two_ separate caches:

- the `argsMemoize` cache for the arguments passed to the output selector, attached to the selector itself.
- the `memoize` cache for the results of the [input selectors](./introduction/getting-started.mdx#input-selectors), attached to `memoizedResultFunc`.

Calling `clearCache` on the selector only clears the first one. To fully reset a selector between tests, clear both:

```ts
selector.clearCache() // clears the `argsMemoize` cache
selector.memoizedResultFunc.clearCache() // clears the `memoize` cache
selector.resetRecomputations()
selector.resetDependencyRecomputations()
```

Alternatively, create the selector inside each test (or in a `beforeEach` block) so that every test starts with a fresh cache.

:::

## Can I share a selector across multiple component instances?

Yes, although if they pass in different arguments, you will need to handle that in order for memoization to work consistently:

- Pass a larger `maxSize` if using `lruMemoize` ( as of 4.1.0+)
- Use [`weakMapMemoize`](./api/weakMapMemoize.mdx) (as of 5.0.0+). If the arguments are ever-changing primitives, pass its [`maxSize` option](./api/weakMapMemoize.mdx#bounding-cache-size-with-maxsize) to bound the cache growth (as of 5.3.0+)

Also note that if the shared selector composes an expensive selector that only depends on the state, the varying arguments will fan out that inner selector's cache and make it re-check its inputs once per distinct argument on every state update. See [Keeping extra arguments away from unary input selectors](./api/weakMapMemoize.mdx#keeping-extra-arguments-away-from-unary-input-selectors).

## Are there TypeScript Typings?

Yes! Reselect is now written in TypeScript itself, so they should Just Work™.

## I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`

Starting in 5.0.0 you should be able to nest up to 30 selectors, but in case you still run into this issue, you can refer to <Link to='https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953'>this
comment</Link> for a discussion of the problem, as
relating to nested selectors.

## How can I make a <Link to='https://github.com/hemanth/functional-programming-jargon#currying'>curried</Link> selector?

Selectors that take arguments are commonly used inside of React-Redux's `useSelector` by using a closure to pass along the extra arguments:

```ts
function TodosList({ category }) {
  const filteredTodos = useSelector(state =>
    selectTodosByCategory(state, category)
  )
}
```

If you prefer to use a curried form instead, you can create a curried selector with this recipe:

{/* START: FAQ/currySelector.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="FAQ/currySelector.ts"
import { createSelector } from 'reselect'
import type { RootState } from './selectorRecomputing'

export const currySelector = <
  State,
  Result,
  Params extends readonly any[],
  AdditionalFields
>(
  selector: ((state: State, ...args: Params) => Result) & AdditionalFields
) => {
  const curriedSelector = (...args: Params) => {
    return (state: State) => {
      return selector(state, ...args)
    }
  }
  return Object.assign(curriedSelector, selector)
}

const selectTodoByIdCurried = currySelector(
  createSelector(
    [(state: RootState) => state.todos, (state: RootState, id: number) => id],
    (todos, id) => todos.find(todo => todo.id === id)
  )
)
```

  </TabItem>
  <TabItem value='js'>

```js title="FAQ/currySelector.js"
import { createSelector } from 'reselect'

export const currySelector = selector => {
  const curriedSelector = (...args) => {
    return state => {
      return selector(state, ...args)
    }
  }
  return Object.assign(curriedSelector, selector)
}

const selectTodoByIdCurried = currySelector(
  createSelector([state => state.todos, (state, id) => id], (todos, id) =>
    todos.find(todo => todo.id === id)
  )
)
```

  </TabItem>
</Tabs>

{/* END: FAQ/currySelector.ts */}

Or for reusability you can do this:

{/* START: FAQ/createCurriedSelector.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="FAQ/createCurriedSelector.ts"
import type { weakMapMemoize, SelectorArray, UnknownMemoizer } from 'reselect'
import { createSelector } from 'reselect'
import { currySelector } from './currySelector'

export const createCurriedSelector = <
  InputSelectors extends SelectorArray,
  Result,
  OverrideMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
  OverrideArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
>(
  ...args: Parameters<
    typeof createSelector<
      InputSelectors,
      Result,
      OverrideMemoizeFunction,
      OverrideArgsMemoizeFunction
    >
  >
) => {
  return currySelector(createSelector(...args))
}
```

  </TabItem>
  <TabItem value='js'>

```js title="FAQ/createCurriedSelector.js"
import { createSelector } from 'reselect'
import { currySelector } from './currySelector'

export const createCurriedSelector = (...args) => {
  return currySelector(createSelector(...args))
}
```

  </TabItem>
</Tabs>

{/* END: FAQ/createCurriedSelector.ts */}

This:

```ts
const selectTodoById = createSelector(
  [(state: RootState) => state.todos, (state: RootState, id: number) => id],
  (todos, id) => todos.find(todo => todo.id === id)
)

selectTodoById(state, 0)
```

Is the same as this:

```ts
selectTodoByIdCurried(0)(state)
```

As before you had to do this:

```ts
const todoById = useSelector(state => selectTodoById(state, id))
```

Now you can do this:

```ts
const todoById = useSelector(selectTodoByIdCurried(id))
```

Another thing you can do if you are using [React-Redux](/react-redux/) is create a custom hook factory function:

{/* START: FAQ/createParametricSelectorHook.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="FAQ/createParametricSelectorHook.ts"
import { useSelector } from 'react-redux'
import { createSelector } from 'reselect'

interface RootState {
  todos: {
    id: number
    completed: boolean
    title: string
    description: string
  }[]
  alerts: { id: number; read: boolean }[]
}

const state: RootState = {
  todos: [
    {
      id: 0,
      completed: false,
      title: 'Figure out if plants are really plotting world domination.',
      description: 'They may be.'
    },
    {
      id: 1,
      completed: true,
      title: 'Practice telekinesis for 15 minutes',
      description: 'Just do it'
    }
  ],
  alerts: [
    { id: 0, read: false },
    { id: 1, read: true }
  ]
}

const selectTodoById = createSelector(
  [(state: RootState) => state.todos, (state: RootState, id: number) => id],
  (todos, id) => todos.find(todo => todo.id === id)
)

export const createParametricSelectorHook = <
  Result,
  Params extends readonly unknown[]
>(
  selector: (state: RootState, ...params: Params) => Result
) => {
  return (...args: Params) => {
    return useSelector((state: RootState) => selector(state, ...args))
  }
}

export const useSelectTodo = createParametricSelectorHook(selectTodoById)
```

  </TabItem>
  <TabItem value='js'>

```js title="FAQ/createParametricSelectorHook.js"
import { useSelector } from 'react-redux'
import { createSelector } from 'reselect'

const state = {
  todos: [
    {
      id: 0,
      completed: false,
      title: 'Figure out if plants are really plotting world domination.',
      description: 'They may be.'
    },
    {
      id: 1,
      completed: true,
      title: 'Practice telekinesis for 15 minutes',
      description: 'Just do it'
    }
  ],
  alerts: [
    { id: 0, read: false },
    { id: 1, read: true }
  ]
}

const selectTodoById = createSelector(
  [state => state.todos, (state, id) => id],
  (todos, id) => todos.find(todo => todo.id === id)
)

export const createParametricSelectorHook = selector => {
  return (...args) => {
    return useSelector(state => selector(state, ...args))
  }
}

export const useSelectTodo = createParametricSelectorHook(selectTodoById)
```

  </TabItem>
</Tabs>

{/* END: FAQ/createParametricSelectorHook.ts */}

And then inside your component:

{/* START: FAQ/MyComponent.tsx */}

<Tabs
  groupId='language'
  defaultValue='tsx'
  values={[
    {label: 'TypeScript', value: 'tsx'},
    {label: 'JavaScript', value: 'jsx'},
  ]}>
  <TabItem value='tsx'>

```tsx title="FAQ/MyComponent.tsx"
import type { FC } from 'react'
import { useSelectTodo } from './createParametricSelectorHook'

interface Props {
  id: number
}

const MyComponent: FC<Props> = ({ id }) => {
  const todo = useSelectTodo(id)
  return <div>{todo?.title}</div>
}
```

  </TabItem>
  <TabItem value='jsx'>

```jsx title="FAQ/MyComponent.jsx"
import { useSelectTodo } from './createParametricSelectorHook'

const MyComponent = ({ id }) => {
  const todo = useSelectTodo(id)
  return <div>{todo?.title}</div>
}
```

  </TabItem>
</Tabs>

{/* END: FAQ/MyComponent.tsx */}

## How can I make a pre-typed version of `createSelector` for my root state?

When used with Redux, it's typical to have all input selectors take `(state: RootState)` as their first argument. Creating a pre-typed version of `createSelector` can shorten that repetition.

You can create a custom typed version of [`createSelector`](./api/createSelector.mdx) by defining a utility type that extends the original `createSelector` function. Here's an example:

```ts
import type {
  OutputSelector,
  Selector,
  SelectorArray,
  UnknownMemoizer
} from 'reselect'
import { createSelector } from 'reselect'

interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean }[]
}

export type TypedCreateSelector<
  State,
  MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
  ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
> = <
  InputSelectors extends readonly Selector<State>[],
  Result,
  OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction,
  OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction
>(
  ...createSelectorArgs: Parameters<
    typeof createSelector<
      InputSelectors,
      Result,
      OverrideMemoizeFunction,
      OverrideArgsMemoizeFunction
    >
  >
) => ReturnType<
  typeof createSelector<
    InputSelectors,
    Result,
    OverrideMemoizeFunction,
    OverrideArgsMemoizeFunction
  >
>

export const createAppSelector: TypedCreateSelector<RootState> = createSelector
```

:::warning

This approach currently only supports [input selectors](./introduction/getting-started.mdx#input-selectors) provided as a single array.

:::

## What if I want to use `createSelector` without memoization?

There may be rare cases when you might want to use `createSelector` for its composition syntax, but without any memoization applied. In that case, create an [identity function](https://en.wikipedia.org/wiki/Identity_function) and use it as the memoizers:

{/* START: FAQ/identity.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="FAQ/identity.ts"
import { createSelectorCreator } from 'reselect'

const identity = <Func extends (...args: any[]) => any>(func: Func) => func

const createNonMemoizedSelector = createSelectorCreator({
  memoize: identity,
  argsMemoize: identity
})
```

  </TabItem>
  <TabItem value='js'>

```js title="FAQ/identity.js"
import { createSelectorCreator } from 'reselect'

const identity = func => func

const createNonMemoizedSelector = createSelectorCreator({
  memoize: identity,
  argsMemoize: identity
})
```

  </TabItem>
</Tabs>

{/* END: FAQ/identity.ts */}

---

### External References (`docs/external-references.mdx`)

---
id: external-references
title: External References
sidebar_label: External References
hide_title: true
description: External References
---

# External References

- [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)
- [Strict equality (reference equality check)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality)
- [Memoization](https://en.wikipedia.org/wiki/Memoization)
- [Identity function](https://en.wikipedia.org/wiki/Identity_function)
- [`useMemo`](https://react.dev/reference/react/useMemo)
- [Re-reselect](https://github.com/toomuchdesign/re-reselect)
- [Redux](/)
- [React](https://react.dev)
- [React-Redux](/react-redux/)
- [Redux Toolkit](/toolkit/)

---

### Related Projects (`docs/related-projects.mdx`)

---
id: related-projects
title: Related Projects
sidebar_label: Related Projects
hide_title: true
description: Related Projects
---

import Link from '@docusaurus/Link'

# Related Projects

## [Re-reselect](https://github.com/toomuchdesign/re-reselect)

Enhances Reselect selectors by wrapping [`createSelector`](./api/createSelector.mdx) and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.

Useful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.

## <Link to='https://github.com/skortchmark9/reselect-tools'>reselect-tools</Link>

- Measure selector recomputations across the app and identify performance bottlenecks
- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension
- Statically export a JSON representation of your selector graph for further analysis

## <Link to='https://github.com/vlanemcev/reselect-debugger-flipper'>reselect-debugger</Link>


<Link to="https://github.com/vlanemcev/flipper-plugin-reselect-debugger">Flipper plugin</Link> and
<Link to="https://github.com/vlanemcev/reselect-debugger-flipper">the connect app</Link> for debugging selectors in **React Native Apps**.

Inspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.

- Selectors Recomputations count in live time across the App for identify performance bottlenecks
- Highlight most recomputed selectors
- Dependency Graph
- Search by Selectors Graph
- Selectors Inputs
- Selectors Output (In case if selector not dependent from external arguments)
- Shows "Not Memoized (NM)" selectors

---

### Tsconfig.Json (`docs/tsconfig.json`)

{
  "compilerOptions": {
    "strict": true,
    "noEmit": true,
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "skipLibCheck": true,
    "types": []
  },
  "files": ["sidebars.ts"]
}

---

### Api CreateSelector (`docs/api/createSelector.mdx`)

---
id: createSelector
title: createSelector
sidebar_label: createSelector
hide_title: true
description: 'createSelector'
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

import Link from '@docusaurus/Link'

# `createSelector`

Accepts one or more "[input selectors](../introduction/getting-started.mdx#input-selectors)" (either as separate arguments or a single array),
a single "[result function](../introduction/getting-started.mdx#result-function)", and an optional options object, and
generates a memoized selector function.

The **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, and typical Reselect usage patterns.

```ts no-emit
const selectTodosByCategory = createSelector(
  [
    // Pass input selectors with typed arguments
    (state: RootState) => state.todos,
    (state: RootState, category: string) => category
  ],
  // Extracted values are passed to the result function for recalculation
  (todos, category) => {
    return todos.filter(t => t.category === category)
  }
)
```

## API Reference

### Parameters

| Name                     | Description                                                                                                                                             |
| :----------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `inputSelectors`         | An array of [input selectors](../introduction/getting-started.mdx#input-selectors), can also be passed as separate arguments.                           |
| `resultFunc`             | A function that takes the results of the input selectors as separate arguments.                                                                         |
| `createSelectorOptions?` | An optional options object that allows for further customization per selector. See [Customizing Selector Options](#customizing-selector-options) below. |

### Returns

A memoized [output selector](../introduction/getting-started.mdx#output-selector).

#### Output Selector Fields

The output selectors created by `createSelector` have several additional properties attached to them:

| Name                            | Description                                                                                                                                                                                                                                                                                        |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `resultFunc`                    | The final function passed to `createSelector`.                                                                                                                                                                                                                                                     |
| `memoizedResultFunc`            | The memoized version of `resultFunc`.                                                                                                                                                                                                                                                              |
| `lastResult`                    | Returns the last result calculated by `memoizedResultFunc`.                                                                                                                                                                                                                                        |
| `dependencies`                  | The array of the input selectors used by `createSelector` to compose `resultFunc`.                                                                                                                                                                                                                 |
| `recomputations`                | Counts the number of times `memoizedResultFunc` has been recalculated.                                                                                                                                                                                                                             |
| `resetRecomputations`           | Resets the count of `recomputations` count to 0.                                                                                                                                                                                                                                                   |
| `dependencyRecomputations`      | Counts the number of times the input selectors ([`dependencies`](../introduction/getting-started.mdx#dependencies)) have been recalculated. This is distinct from `recomputations`, which tracks the recalculations of the [result function](../introduction/getting-started.mdx#result-function). |
| `resetDependencyRecomputations` | Resets the `dependencyRecomputations` count to 0.                                                                                                                                                                                                                                                  |
| `memoize`                       | Function used to memoize the `resultFunc`.                                                                                                                                                                                                                                                         |
| `argsMemoize`                   | Function used to memoize the arguments passed into the output selector.                                                                                                                                                                                                                            |

:::note Clearing the cache

Both the output selector and its `memoizedResultFunc` expose the fields attached by their memoize function — for the built-in memoizers that means `clearCache`, `resultsCount` and `resetResultsCount`.

Because a selector keeps a [separate cache for its arguments (`argsMemoize`) and for its result (`memoize`)](../introduction/how-does-reselect-work.mdx#cascading-memoization), fully clearing it requires calling `clearCache` on **both**:

```ts
mySelector.clearCache() // clears the `argsMemoize` cache
mySelector.memoizedResultFunc.clearCache() // clears the `memoize` cache
```

:::

### Type Parameters

| Name                          | Description                                                                                                                                                                                                                 |
| :---------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `InputSelectors`              | The type of the input selectors array.                                                                                                                                                                                      |
| `Result`                      | The return type of the result function as well as the output selector.                                                                                                                                                      |
| `OverrideMemoizeFunction`     | The type of the optional `memoize` function that could be passed into the options object to override the original `memoize` function that was initially passed into [`createSelectorCreator`](./createSelectorCreator.mdx). |
| `OverrideArgsMemoizeFunction` | The type of the optional `argsMemoize` function that could be passed into the options object to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`.                        |

## Defining a Pre-Typed `createSelector`

As of Reselect 5.1.0, you can create a "pre-typed" version of `createSelector` where the `state` type is predefined. This allows you to set the `state` type once, eliminating the need to specify it with every `createSelector` call.

To do this, you can call `createSelector.withTypes<StateType>()`:

{/* START: createSelector/withTypes.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="createSelector/withTypes.ts"
import { createSelector } from 'reselect'

export interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean }[]
}

export const createAppSelector = createSelector.withTypes<RootState>()

const selectTodoIds = createAppSelector(
  [
    // Type of `state` is set to `RootState`, no need to manually set the type
    // highlight-start
    state => state.todos
    // highlight-end
  ],
  todos => todos.map(({ id }) => id)
)
```

  </TabItem>
  <TabItem value='js'>

```js title="createSelector/withTypes.js"
import { createSelector } from 'reselect'

export const createAppSelector = createSelector.withTypes()

const selectTodoIds = createAppSelector(
  [
    // Type of `state` is set to `RootState`, no need to manually set the type
    // highlight-start
    state => state.todos
    // highlight-end
  ],
  todos => todos.map(({ id }) => id)
)
```

  </TabItem>
</Tabs>

{/* END: createSelector/withTypes.ts */}

Import and use the pre-typed `createAppSelector` instead of the original, and the type for state will be used automatically.

:::danger Known Limitations

Currently this approach only works if input selectors are provided as a single array.

If you pass the input selectors as separate inline arguments, the parameter types of the result function will not be inferred.
As a workaround you can either

1. Wrap your input selectors in a single array
2. You can annotate the parameter types of the result function:

{/* START: createSelector/annotateResultFunction.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="createSelector/annotateResultFunction.ts"
import { createSelector } from 'reselect'

interface Todo {
  id: number
  completed: boolean
}

interface Alert {
  id: number
  read: boolean
}

export interface RootState {
  todos: Todo[]
  alerts: Alert[]
}

export const createAppSelector = createSelector.withTypes<RootState>()

const selectTodoIds = createAppSelector(
  // Type of `state` is set to `RootState`, no need to manually set the type
  state => state.todos,
  // ❌ Known limitation: Parameter types are not inferred in this scenario
  // so you will have to manually annotate them.
  // highlight-start
  (todos: Todo[]) => todos.map(({ id }) => id)
  // highlight-end
)
```

  </TabItem>
  <TabItem value='js'>

```js title="createSelector/annotateResultFunction.js"
import { createSelector } from 'reselect'

export const createAppSelector = createSelector.withTypes()

const selectTodoIds = createAppSelector(
  // Type of `state` is set to `RootState`, no need to manually set the type
  state => state.todos,
  // ❌ Known limitation: Parameter types are not inferred in this scenario
  // so you will have to manually annotate them.
  // highlight-start
  todos => todos.map(({ id }) => id)
  // highlight-end
)
```

  </TabItem>
</Tabs>

{/* END: createSelector/annotateResultFunction.ts */}

:::

:::tip

You can also use this API with [`createSelectorCreator`](./createSelectorCreator.mdx) to create a pre-typed custom selector creator:

{/* START: createSelector/createAppSelector.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="createSelector/createAppSelector.ts"
import microMemoize from 'micro-memoize'
import { shallowEqual } from 'react-redux'
import { createSelectorCreator, lruMemoize } from 'reselect'

export interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean }[]
}

export const createAppSelector = createSelectorCreator({
  memoize: lruMemoize,
  argsMemoize: microMemoize,
  memoizeOptions: {
    maxSize: 10,
    equalityCheck: shallowEqual,
    resultEqualityCheck: shallowEqual
  },
  argsMemoizeOptions: {
    isEqual: shallowEqual,
    maxSize: 10
  },
  devModeChecks: {
    identityFunctionCheck: 'never',
    inputStabilityCheck: 'always'
  }
}).withTypes<RootState>()

const selectReadAlerts = createAppSelector(
  [
    // Type of `state` is set to `RootState`, no need to manually set the type
    // highlight-start
    state => state.alerts
    // highlight-end
  ],
  alerts => alerts.filter(({ read }) => read)
)
```

  </TabItem>
  <TabItem value='js'>

```js title="createSelector/createAppSelector.js"
import microMemoize from 'micro-memoize'
import { shallowEqual } from 'react-redux'
import { createSelectorCreator, lruMemoize } from 'reselect'

export const createAppSelector = createSelectorCreator({
  memoize: lruMemoize,
  argsMemoize: microMemoize,
  memoizeOptions: {
    maxSize: 10,
    equalityCheck: shallowEqual,
    resultEqualityCheck: shallowEqual
  },
  argsMemoizeOptions: {
    isEqual: shallowEqual,
    maxSize: 10
  },
  devModeChecks: {
    identityFunctionCheck: 'never',
    inputStabilityCheck: 'always'
  }
}).withTypes()

const selectReadAlerts = createAppSelector(
  [
    // Type of `state` is set to `RootState`, no need to manually set the type
    // highlight-start
    state => state.alerts
    // highlight-end
  ],
  alerts => alerts.filter(({ read }) => read)
)
```

  </TabItem>
</Tabs>

{/* END: createSelector/createAppSelector.ts */}

:::

## Usage Guide

### Memoization Functions

`createSelector` does not implement memoization itself — it delegates to a **memoize function**: a higher-order function that wraps another function and returns a caching version of it, so that repeated calls with known arguments return the cached result instead of recomputing.

Each selector uses a memoize function at two levels, following the [cascading memoization](../introduction/how-does-reselect-work.mdx#cascading-memoization) pattern:

- `argsMemoize` memoizes the generated selector itself, based on the arguments it was called with (such as `state`). If the arguments match a previous call, nothing else runs.
- `memoize` memoizes the [result function](../introduction/getting-started.mdx#result-function), based on the values returned by the [input selectors](../introduction/getting-started.mdx#input-selectors). If those values match, the cached result is returned without recalculating.

Reselect ships two memoize functions: [`weakMapMemoize`](./weakMapMemoize.mdx) (the default) and [`lruMemoize`](./lruMemoize.mdx).

Both levels can be overridden independently, per selector via the `memoize`/`argsMemoize` options, or for a whole family of selectors via [`createSelectorCreator`](./createSelectorCreator.mdx). Third-party memoizers such as `micro-memoize` work as well.

:::info Default Memoization

Since v5.0.0, `createSelector` uses `weakMapMemoize` as the default for both `memoize` and `argsMemoize`. In v4.x the default was `lruMemoize` (previously named `defaultMemoize`) with a cache size of **1**, meaning a selector only remembered its most recent call.

`weakMapMemoize` instead provides an effectively **unlimited** cache size keyed on argument identity, which fixes the common "cache size of 1" problem when the same selector is called with many different arguments (e.g. `useSelector(state => selectItemById(state, id))` across a list). Results keyed by object arguments are released as those arguments are garbage-collected; results keyed by primitive arguments stay cached until cleared. See [`weakMapMemoize`](./weakMapMemoize.mdx) for the full behavior and tradeoffs.

Because these are the defaults, you **do not** need to pass `memoize`/`argsMemoize` unless you want to override them (for example, to use `lruMemoize` with a custom `equalityCheck`).

:::

### Customizing Selector Options

There are two places to apply these options, depending on how widely you want them to apply.

#### Per instance, with the options object

`createSelector` accepts an options object as its final argument. Options passed there apply to **that one selector instance**: `memoize` and `argsMemoize` choose the memoize function for each level, while `memoizeOptions` and `argsMemoizeOptions` are forwarded to those functions as their configuration.

```ts no-emit
const selectTodoIds = createSelector(
  [(state: RootState) => state.todos],
  todos => todos.map(todo => todo.id),
  {
    memoize: lruMemoize,
    memoizeOptions: { resultEqualityCheck: shallowEqual }
  }
)
```

This is the right place for a one-off: a single selector that needs a custom equality check or a different memoizer than the rest of the app.

#### Baked in, with `createSelectorCreator`

If several selectors need the same configuration, repeating the options object at every call site gets noisy and easy to forget. `createSelectorCreator` accepts the same options once and returns a customized `createSelector` with those options baked in:

```ts no-emit
const createShallowEqualSelector = createSelectorCreator({
  memoize: lruMemoize,
  memoizeOptions: { resultEqualityCheck: shallowEqual }
})

// Every selector made with this creator shares the configuration
const selectTodoIds = createShallowEqualSelector(
  [(state: RootState) => state.todos],
  todos => todos.map(todo => todo.id)
)
```

In fact, the default `createSelector` is itself the result of calling `createSelectorCreator` with `weakMapMemoize`.

The two compose: a selector made with a custom creator can still pass its own options object, and those per-instance options override the baked-in ones for that selector only.

---

### Api CreateSelectorCreator (`docs/api/createSelectorCreator.mdx`)

---
id: createSelectorCreator
title: createSelectorCreator
sidebar_label: createSelectorCreator
hide_title: true
description: 'createSelectorCreator'
---

# `createSelectorCreator`

Accepts either a `memoize` function and `...memoizeOptions` rest parameter, or since 5.0.0 an `options` object containing a `memoize` function and creates a custom selector creator function.

## API Reference

### Parameters (since 5.0.0)

| Name                           | Description                                                                                                                                                                                                                                                                                                                 |
| :----------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options`                      | An options object containing the `memoize` function responsible for memoizing the `resultFunc` inside [`createSelector`](./createSelector.mdx) (e.g., `lruMemoize` or `weakMapMemoize`). It also provides additional options for customizing memoization. While the `memoize` property is mandatory, the rest are optional. |
| `options.argsMemoize?`         | The optional memoize function that is used to memoize the arguments passed into the [output selector](../introduction/getting-started.mdx#output-selector) generated by `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). <br /> **`Default`** = `lruMemoize` before 5.0.0 and `weakMapMemoize` after              |
| `options.argsMemoizeOptions?`  | Optional configuration options for the `argsMemoize` function. These options are passed to the `argsMemoize` function as the second argument. <br /> since 5.0.0                                                                                                                                                            |
| `options.inputStabilityCheck?` | Overrides the global input stability check for the selector. Possible values are: <br /> `once` - Run only the first time the selector is called. <br /> `always` - Run every time the selector is called. <br /> `never` - Never run the input stability check. <br /> **`Default`** = `'once'` <br /> since 5.0.0         |
| `options.memoize`              | The memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). since 5.0.0                                                                                                                                                                                 |
| `options.memoizeOptions?`      | Optional configuration options for the `memoize` function. These options are passed to the `memoize` function as the second argument. <br /> since 5.0.0                                                                                                                                                                    |

### Parameters (legacy)

| Name                        | Description                                                                                                                                        |
| :-------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |
| `memoize`                   | The `memoize` function responsible for memoizing the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).                |
| `...memoizeOptionsFromArgs` | Optional configuration options for the memoization function. These options are then passed to the memoize function as the second argument onwards. |

### Returns

A customized `createSelector` function.

### Type Parameters

| Name                  | Description                                                                                                                                                                                                                                            |
| :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MemoizeFunction`     | The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).                                                                                                            |
| `ArgsMemoizeFunction` | The type of the optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used. |

## Usage Guide

### Examples

#### Using `options` (since 5.0.0)

```ts
const customCreateSelector = createSelectorCreator({
  memoize: customMemoize, // Function to be used to memoize `resultFunc`
  memoizeOptions: [memoizeOption1, memoizeOption2], // Options passed to `customMemoize` as the second argument onwards
  argsMemoize: customArgsMemoize, // Function to be used to memoize the selector's arguments
  argsMemoizeOptions: [argsMemoizeOption1, argsMemoizeOption2] // Options passed to `customArgsMemoize` as the second argument onwards
})

const customSelector = customCreateSelector(
  [inputSelector1, inputSelector2],
  resultFunc // `resultFunc` will be passed as the first argument to `customMemoize`
)

customSelector(
  ...selectorArgs // Will be memoized by `customArgsMemoize`
)
```

#### Using `memoize` and `...memoizeOptions`

`createSelectorCreator` can be used to make a customized version of [`createSelector`](./createSelector.mdx).

The `memoize` argument is a memoization function to replace the default configured memoizer (normally `weakMapMemoize`).

The `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:

```ts
const customSelectorCreator = createSelectorCreator(
  customMemoize, // Function to be used to memoize `resultFunc`
  option1, // `option1` will be passed as second argument to `customMemoize`
  option2, // `option2` will be passed as third argument to `customMemoize`
  option3 // `option3` will be passed as fourth argument to `customMemoize`
)

const customSelector = customSelectorCreator(
  [inputSelector1, inputSelector2],
  resultFunc // `resultFunc` will be passed as first argument to `customMemoize`
)
```

Internally `customSelector` calls the memoize function as follows:

```ts
customMemoize(resultFunc, option1, option2, option3)
```

#### Customize `equalityCheck` for `lruMemoize`

```js
import { createSelectorCreator, lruMemoize } from 'reselect'
import isEqual from 'lodash.isequal'

// create a "selector creator" that uses lodash.isequal instead of ===
const createDeepEqualSelector = createSelectorCreator(lruMemoize, isEqual)

// use the new "selector creator" to create a selector
const selectSum = createDeepEqualSelector(
  [state => state.values.filter(val => val < 5)],
  values => values.reduce((acc, val) => acc + val, 0)
)
```

#### Use memoize function from Lodash for an unbounded cache

```js
import { createSelectorCreator } from 'reselect'
import memoize from 'lodash.memoize'

const hashFn = (...args) =>
  args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')

const customSelectorCreator = createSelectorCreator(memoize, hashFn)

const selector = customSelectorCreator(
  [state => state.a, state => state.b],
  (a, b) => a + b
)
```

---

### Api CreateStructuredSelector (`docs/api/createStructuredSelector.mdx`)

---
id: createStructuredSelector
title: createStructuredSelector
sidebar_label: createStructuredSelector
hide_title: true
description: 'createStructuredSelector'
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

# `createStructuredSelector`

A convenience function that simplifies returning an object made up of selector results.

## API Reference

### Parameters

| Name                   | Description                                                                                  |
| :--------------------- | :------------------------------------------------------------------------------------------- |
| `inputSelectorsObject` | A key value pair consisting of input selectors.                                              |
| `selectorCreator?`     | A custom selector creator function. It defaults to [`createSelector`](./createSelector.mdx). |

### Returns

A memoized structured selector.

### Type Parameters

| Name                   | Description                                                                                                                                            |
| :--------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `InputSelectorsObject` | The shape of the [input selectors](../introduction/getting-started.mdx#input-selectors) object.                                                        |
| `MemoizeFunction`      | The type of the memoize function that is used to create the structured selector. It defaults to `weakMapMemoize`.                                      |
| `ArgsMemoizeFunction`  | The type of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `weakMapMemoize`. |

## Usage Guide

### Examples

#### Modern Use Case

{/* START: createStructuredSelector/modernUseCase.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="createStructuredSelector/modernUseCase.ts"
import { createSelector, createStructuredSelector } from 'reselect'

export interface RootState {
  todos: {
    id: number
    completed: boolean
    title: string
    description: string
  }[]
  alerts: { id: number; read: boolean }[]
}

// This:
export const structuredSelector = createStructuredSelector(
  {
    todos: (state: RootState) => state.todos,
    alerts: (state: RootState) => state.alerts,
    todoById: (state: RootState, id: number) => state.todos[id]
  },
  createSelector
)

// Is essentially the same as this:
export const selector = createSelector(
  [
    (state: RootState) => state.todos,
    (state: RootState) => state.alerts,
    (state: RootState, id: number) => state.todos[id]
  ],
  (todos, alerts, todoById) => {
    return {
      todos,
      alerts,
      todoById
    }
  }
)
```

  </TabItem>
  <TabItem value='js'>

```js title="createStructuredSelector/modernUseCase.js"
import { createSelector, createStructuredSelector } from 'reselect'

// This:
export const structuredSelector = createStructuredSelector(
  {
    todos: state => state.todos,
    alerts: state => state.alerts,
    todoById: (state, id) => state.todos[id]
  },
  createSelector
)

// Is essentially the same as this:
export const selector = createSelector(
  [state => state.todos, state => state.alerts, (state, id) => state.todos[id]],
  (todos, alerts, todoById) => {
    return {
      todos,
      alerts,
      todoById
    }
  }
)
```

  </TabItem>
</Tabs>

{/* END: createStructuredSelector/modernUseCase.ts */}

In your component:

{/* START: createStructuredSelector/MyComponent.tsx */}

<Tabs
  groupId='language'
  defaultValue='tsx'
  values={[
    {label: 'TypeScript', value: 'tsx'},
    {label: 'JavaScript', value: 'jsx'},
  ]}>
  <TabItem value='tsx'>

```tsx title="createStructuredSelector/MyComponent.tsx"
import type { RootState } from 'createStructuredSelector/modernUseCase'
import { structuredSelector } from 'createStructuredSelector/modernUseCase'
import type { FC } from 'react'
import { useSelector } from 'react-redux'

interface Props {
  id: number
}

const MyComponent: FC<Props> = ({ id }) => {
  const { todos, alerts, todoById } = useSelector((state: RootState) =>
    structuredSelector(state, id)
  )

  return (
    <div>
      Next to do is:
      <h2>{todoById.title}</h2>
      <p>Description: {todoById.description}</p>
      <ul>
        <h3>All other to dos:</h3>
        {todos.map(todo => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  )
}
```

  </TabItem>
  <TabItem value='jsx'>

```jsx title="createStructuredSelector/MyComponent.jsx"
import { structuredSelector } from 'createStructuredSelector/modernUseCase'
import { useSelector } from 'react-redux'

const MyComponent = ({ id }) => {
  const { todos, alerts, todoById } = useSelector(state =>
    structuredSelector(state, id)
  )

  return (
    <div>
      Next to do is:
      <h2>{todoById.title}</h2>
      <p>Description: {todoById.description}</p>
      <ul>
        <h3>All other to dos:</h3>
        {todos.map(todo => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  )
}
```

  </TabItem>
</Tabs>

{/* END: createStructuredSelector/MyComponent.tsx */}

#### Simple Use Case

```ts
const selectA = state => state.a
const selectB = state => state.b

// The result function in the following selector
// is simply building an object from the input selectors
const structuredSelector = createSelector(selectA, selectB, (a, b) => ({
  x: a,
  y: b
}))

const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
```

`createStructuredSelector` takes an object whose properties are input selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectorsObject` argument, but with the selectors replaced with their values.

```ts
const selectA = state => state.a
const selectB = state => state.b

const structuredSelector = createStructuredSelector({
  x: selectA,
  y: selectB
})

const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
```

Structured selectors can be nested:

```ts
const nestedSelector = createStructuredSelector({
  subA: createStructuredSelector({
    selectorA,
    selectorB
  }),
  subB: createStructuredSelector({
    selectorC,
    selectorD
  })
})
```

## Defining a Pre-Typed `createStructuredSelector`

As of Reselect 5.1.0, you can create a "pre-typed" version of `createStructuredSelector` where the `state` type is predefined. This allows you to set the `state` type once, eliminating the need to specify it with every `createStructuredSelector` call.

To do this, you can call `createStructuredSelector.withTypes<StateType>()`:

{/* START: createStructuredSelector/withTypes.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="createStructuredSelector/withTypes.ts"
import { createStructuredSelector } from 'reselect'

export interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean }[]
}

export const createStructuredAppSelector =
  createStructuredSelector.withTypes<RootState>()

const structuredAppSelector = createStructuredAppSelector({
  // Type of `state` is set to `RootState`, no need to manually set the type
  // highlight-start
  todos: state => state.todos,
  // highlight-end
  alerts: state => state.alerts,
  todoById: (state, id: number) => state.todos[id]
})
```

  </TabItem>
  <TabItem value='js'>

```js title="createStructuredSelector/withTypes.js"
import { createStructuredSelector } from 'reselect'

export const createStructuredAppSelector = createStructuredSelector.withTypes()

const structuredAppSelector = createStructuredAppSelector({
  // Type of `state` is set to `RootState`, no need to manually set the type
  // highlight-start
  todos: state => state.todos,
  // highlight-end
  alerts: state => state.alerts,
  todoById: (state, id) => state.todos[id]
})
```

  </TabItem>
</Tabs>

{/* END: createStructuredSelector/withTypes.ts */}

---

### Api Development Only Checks (`docs/api/development-only-checks.mdx`)

---
id: development-only-checks
title: Development-Only Checks
sidebar_label: Development-Only Checks
sidebar_position: 1
hide_title: true
description: Development-Only Checks
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

# Development-Only Checks

In development mode, Reselect runs extra checks on your selectors and warns about common mistakes:

| Check                                             | What it catches                                                                                                                           |
| :------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------- |
| [`inputStabilityCheck`](#inputstabilitycheck)     | [input selectors](../introduction/getting-started.mdx#input-selectors) that return a new reference on every run, which breaks memoization |
| [`identityFunctionCheck`](#identityfunctioncheck) | Result functions that return their argument unchanged, which memoize nothing useful                                                       |
| [`cacheSizeCheck`](#cachesizecheck)               | [`weakMapMemoize`](./weakMapMemoize.mdx) caches that grow without bound from ever-changing primitive arguments                            |

:::info

All development-only checks are automatically disabled in production environments.

:::

## Configuring the checks

Every check runs with one of three frequencies:

```ts
type DevModeCheckFrequency = 'always' | 'once' | 'never'
```

| Possible Values | Description                                                                                                                                   |
| :-------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- |
| `once`          | Run the check once per selector: on the first call for the stability checks, or the first time the threshold is crossed for `cacheSizeCheck`. |
| `always`        | Run the check on every call.                                                                                                                  |
| `never`         | Never run the check.                                                                                                                          |

The default for every check is `once`: catching a mistake does not require checking on every call, so the checks stay cheap.

### Globally with `setGlobalDevModeChecks`

The `setGlobalDevModeChecks` function changes the frequency for all selectors. It takes a partial object, so set only the checks you want to change:

```ts
import { setGlobalDevModeChecks } from 'reselect'

// Run the input stability check every time any selector is called.
setGlobalDevModeChecks({ inputStabilityCheck: 'always' })

// Turn off the identity function check entirely.
setGlobalDevModeChecks({ identityFunctionCheck: 'never' })
```

### Per selector with the `devModeChecks` option

Individual selectors can override the global setting by passing a `devModeChecks` option to [`createSelector`](./createSelector.mdx):

```ts
const selectTodoIds = createSelector(
  [(state: RootState) => state.todos],
  todos => todos.map(todo => todo.id),
  {
    devModeChecks: {
      inputStabilityCheck: 'always',
      identityFunctionCheck: 'never'
    }
  }
)
```

:::warning

A `devModeChecks` option always overrides the global setting for that selector, in both directions: it can turn a check on for one selector after globally disabling it, or turn it off for one selector that is a known false positive.

:::

:::caution

`cacheSizeCheck` can only be configured globally. It runs inside [`weakMapMemoize`](./weakMapMemoize.mdx) itself, which never sees `createSelector`'s options, so passing `devModeChecks: { cacheSizeCheck: ... }` to a selector has no effect.

:::

## `inputStabilityCheck`

Due to how [cascading memoization](../introduction/how-does-reselect-work.mdx#cascading-memoization) works in Reselect, it is crucial that your [input selectors](../introduction/getting-started.mdx#input-selectors) do not return a new reference on each run. If an input selector always returns a new reference, like

```ts
state => ({ a: state.a, b: state.b })
```

or

```ts
state => state.todos.map(todo => todo.id)
```

the selector will never memoize properly.

Since this is a common mistake, [`createSelector`](./createSelector.mdx) runs the input selectors twice during the first call to the selector. If the results appear to be different for the same call, it logs a warning with the arguments and the two different sets of extracted input values.

Turning the check up to `always` is useful while debugging a selector that recomputes more than expected:

{/* START: development-only-checks/inputStabilityCheck.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="development-only-checks/inputStabilityCheck.ts"
import { createSelector } from 'reselect'

interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean }[]
}

// Create a selector that double-checks the results of input selectors every time it runs.
const selectCompletedTodosLength = createSelector(
  [
    // ❌ Incorrect Use Case: This input selector will not be
    // memoized properly since it always returns a new reference.
    (state: RootState) =>
      state.todos.filter(({ completed }) => completed === true)
  ],
  completedTodos => completedTodos.length,
  // Will override the global setting.
  { devModeChecks: { inputStabilityCheck: 'always' } }
)
```

  </TabItem>
  <TabItem value='js'>

```js title="development-only-checks/inputStabilityCheck.js"
import { createSelector } from 'reselect'

// Create a selector that double-checks the results of input selectors every time it runs.
const selectCompletedTodosLength = createSelector(
  [
    // ❌ Incorrect Use Case: This input selector will not be
    // memoized properly since it always returns a new reference.
    state => state.todos.filter(({ completed }) => completed === true)
  ],
  completedTodos => completedTodos.length,
  // Will override the global setting.
  { devModeChecks: { inputStabilityCheck: 'always' } }
)
```

  </TabItem>
</Tabs>

{/* END: development-only-checks/inputStabilityCheck.ts */}

## `identityFunctionCheck`

Reselect relies on a separation of concerns between extraction and transformation logic:

- **Extraction logic** retrieves data from a broader state, like `state => state.todos`. It belongs in [input selectors](../introduction/getting-started.mdx#input-selectors).
- **Transformation logic** manipulates or formats that data, like `todos => todos.map(({ id }) => id)`. It belongs in the [result function](../introduction/getting-started.mdx#result-function).

Memoization only works when the two are properly separated: the input selector results are what get compared between calls, and the result function is what gets skipped on a cache hit. A result function that returns its argument unchanged means the selector does nothing useful:

```ts
// ❌ Incorrect Use Case: This will not memoize correctly, and does nothing useful!
const brokenSelector = createSelector(
  // ✔️ GOOD: Contains extraction logic.
  [(state: RootState) => state.todos],
  // ❌ BAD: Does not contain transformation logic.
  todos => todos
)
```

This check detects that pattern and logs a warning the first time the selector runs:

{/* START: development-only-checks/identityFunctionCheck.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="development-only-checks/identityFunctionCheck.ts"
import { createSelector } from 'reselect'

interface RootState {
  todos: { id: number; completed: boolean }[]
  alerts: { id: number; read: boolean }[]
}

// Create a selector that checks to see if the result function is an identity function.
const selectTodos = createSelector(
  // ✔️ GOOD: Contains extraction logic.
  [(state: RootState) => state.todos],
  // ❌ BAD: Does not contain transformation logic.
  todos => todos,
  // Will override the global setting.
  { devModeChecks: { identityFunctionCheck: 'always' } }
)
```

  </TabItem>
  <TabItem value='js'>

```js title="development-only-checks/identityFunctionCheck.js"
import { createSelector } from 'reselect'

// Create a selector that checks to see if the result function is an identity function.
const selectTodos = createSelector(
  // ✔️ GOOD: Contains extraction logic.
  [state => state.todos],
  // ❌ BAD: Does not contain transformation logic.
  todos => todos,
  // Will override the global setting.
  { devModeChecks: { identityFunctionCheck: 'always' } }
)
```

  </TabItem>
</Tabs>

{/* END: development-only-checks/identityFunctionCheck.ts */}

## `cacheSizeCheck`

[`weakMapMemoize`](./weakMapMemoize.mdx) (the default memoizer since 5.0) keys its cache
tree by argument identity, and the two kinds of arguments age out of the cache
very differently:

- Results keyed by an **object or function** argument live in a `WeakMap`. Once that argument is garbage-collected, the cached result goes with it.
- Results keyed by a **primitive** argument (a string, number, or boolean) live in a regular `Map`. They are held strongly and are only released by calling `.clearCache()` on the memoized function.

A selector that keeps seeing new primitive values in the same argument position — ids, offsets, timestamps, page numbers — therefore grows its cache without bound. A paginated selector is the canonical case:

```ts
const selectVisibleItems = createSelector(
  [
    (state: RootState) => state.items,
    (state: RootState, from: number) => from,
    (state: RootState, to: number) => to
  ],
  (items, from, to) => items.slice(from, to)
)
```

As the user scrolls, every `(from, to)` pair ever passed stays cached: the sliced arrays for `(0, 10)`, `(1, 11)`, `(2, 12)`, and so on are all retained for as long as `state.items` is alive, long after those windows scrolled out of view.

This check counts the distinct primitive values cached for each argument position. When a single position exceeds **1,000** distinct values, it logs a warning naming the memoized function. The count is per argument position, so a per-item selector called with a bounded set of ids will not trip it — the warning fires on the _unbounded_ pattern, not on legitimate wide caches.

If you see this warning, the usual fixes are:

- Pass the [`maxSize` option](./weakMapMemoize#bounding-cache-size-with-maxsize) to bound the cache (as of 5.3.0). Note that bounding a selector created by [`createSelector`](./createSelector.mdx) requires `maxSize` in both `memoizeOptions` and `argsMemoizeOptions`.
- Switch that selector to [`lruMemoize`](./lruMemoize.mdx), which holds a fixed number of results with exact LRU eviction.
- Call `.clearCache()` at a suitable point, such as when the data it derives from is replaced. Clearing the cache also re-arms the warning, so you will hear about it again if the cache regrows.

Unlike the other checks, `cacheSizeCheck` is configured globally only (see the caution [above](#per-selector-with-the-devmodechecks-option)):

```ts
import { setGlobalDevModeChecks } from 'reselect'

// Warn once per memoized function. (default)
setGlobalDevModeChecks({ cacheSizeCheck: 'once' })

// Warn on every cache insertion past the threshold.
setGlobalDevModeChecks({ cacheSizeCheck: 'always' })

// Never check cache sizes.
setGlobalDevModeChecks({ cacheSizeCheck: 'never' })
```

---

### Api LruMemoize (`docs/api/lruMemoize.mdx`)

---
id: lruMemoize
title: lruMemoize
sidebar_label: lruMemoize
hide_title: true
description: 'lruMemoize'
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

# `lruMemoize`

A memoization function that uses a provided equality check function to compare its inputs. This was originally known as `defaultMemoize`, and was the default inside of [`createSelector`](./createSelector.mdx) up through version 4.x.

It has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (since 4.1.0).

It determines if an argument has changed by calling the `equalityCheck` function. As `lruMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using [reference equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality):

{/* START: lruMemoize/referenceEqualityCheck.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="lruMemoize/referenceEqualityCheck.ts"
const referenceEqualityCheck = (previousValue: any, currentValue: any) => {
  return previousValue === currentValue
}
```

  </TabItem>
  <TabItem value='js'>

```js title="lruMemoize/referenceEqualityCheck.js"
const referenceEqualityCheck = (previousValue, currentValue) => {
  return previousValue === currentValue
}
```

  </TabItem>
</Tabs>

{/* END: lruMemoize/referenceEqualityCheck.ts */}

## API Reference

### Parameters

| Name                     | Description                                               |
| :----------------------- | :-------------------------------------------------------- |
| `func`                   | The function to be memoized.                              |
| `equalityCheckOrOptions` | Either an equality check function or an `options` object. |

Since 4.1.0, `lruMemoize` also accepts an options object as its first argument instead of an `equalityCheck` function. The `options` object may contain:

```ts
type EqualityFn<T = any> = (a: T, b: T) => boolean

interface LruMemoizeOptions<Result = any> {
  equalityCheck?: EqualityFn
  resultEqualityCheck?: EqualityFn<Result>
  maxSize?: number
}
```

| Name                  | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `equalityCheck`       | Used to compare the individual arguments of the provided calculation function. <br /> **`Default`** = `defaultEqualityCheck`                                                                                                                                                                                                                                                                                                                                         |
| `resultEqualityCheck` | If provided, used to compare a newly generated output value against previous values in the cache. If a match is found, the old value is returned. This addresses the common <code>todos.map(todo => todo.id)</code> use case, where an update to another field in the original data causes a recalculation due to changed references, but the output is still effectively the same.                                                                                  |
| `maxSize`             | The cache size for the selector. If greater than 1, the selector will use an LRU cache internally. <br /> **`Default`** = 1 <br /> As of 5.3.0, [`weakMapMemoize`](./weakMapMemoize.mdx) also accepts a [`maxSize` option](./weakMapMemoize#bounding-cache-size-with-maxsize). The difference: `lruMemoize` keeps an exact bound with per-entry LRU eviction, while `weakMapMemoize` uses a cheaper generational bound of roughly `2 * maxSize` with batch eviction. |

:::warning

If `resultEqualityCheck` is used inside `argsMemoizeOptions` it has no effect.

:::

### Returns

A memoized function with a `.clearCache()` method attached.

### Type Parameters

| Name   | Description                                |
| :----- | :----------------------------------------- |
| `Func` | The type of the function that is memoized. |

## Usage Guide

### Examples

#### Using `lruMemoize` with `createSelector`

{/* START: lruMemoize/usingWithCreateSelector.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="lruMemoize/usingWithCreateSelector.ts"
import { shallowEqual } from 'react-redux'
import { createSelector, lruMemoize } from 'reselect'

export interface RootState {
  todos: {
    id: number
    completed: boolean
    title: string
    description: string
  }[]
  alerts: { id: number; read: boolean }[]
}

const selectTodoIds = createSelector(
  [(state: RootState) => state.todos],
  todos => todos.map(todo => todo.id),
  {
    memoize: lruMemoize,
    memoizeOptions: {
      equalityCheck: shallowEqual,
      resultEqualityCheck: shallowEqual,
      maxSize: 10
    },
    argsMemoize: lruMemoize,
    argsMemoizeOptions: {
      equalityCheck: shallowEqual,
      resultEqualityCheck: shallowEqual,
      maxSize: 10
    }
  }
)
```

  </TabItem>
  <TabItem value='js'>

```js title="lruMemoize/usingWithCreateSelector.js"
import { shallowEqual } from 'react-redux'
import { createSelector, lruMemoize } from 'reselect'

const selectTodoIds = createSelector(
  [state => state.todos],
  todos => todos.map(todo => todo.id),
  {
    memoize: lruMemoize,
    memoizeOptions: {
      equalityCheck: shallowEqual,
      resultEqualityCheck: shallowEqual,
      maxSize: 10
    },
    argsMemoize: lruMemoize,
    argsMemoizeOptions: {
      equalityCheck: shallowEqual,
      resultEqualityCheck: shallowEqual,
      maxSize: 10
    }
  }
)
```

  </TabItem>
</Tabs>

{/* END: lruMemoize/usingWithCreateSelector.ts */}

#### Using `lruMemoize` with `createSelectorCreator`

{/* START: lruMemoize/usingWithCreateSelectorCreator.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="lruMemoize/usingWithCreateSelectorCreator.ts"
import { shallowEqual } from 'react-redux'
import { createSelectorCreator, lruMemoize } from 'reselect'

export interface RootState {
  todos: {
    id: number
    completed: boolean
    title: string
    description: string
  }[]
  alerts: { id: number; read: boolean }[]
}

const createSelectorShallowEqual = createSelectorCreator({
  memoize: lruMemoize,
  memoizeOptions: {
    equalityCheck: shallowEqual,
    resultEqualityCheck: shallowEqual,
    maxSize: 10
  },
  argsMemoize: lruMemoize,
  argsMemoizeOptions: {
    equalityCheck: shallowEqual,
    resultEqualityCheck: shallowEqual,
    maxSize: 10
  }
})

const selectTodoIds = createSelectorShallowEqual(
  [(state: RootState) => state.todos],
  todos => todos.map(todo => todo.id)
)
```

  </TabItem>
  <TabItem value='js'>

```js title="lruMemoize/usingWithCreateSelectorCreator.js"
import { shallowEqual } from 'react-redux'
import { createSelectorCreator, lruMemoize } from 'reselect'

const createSelectorShallowEqual = createSelectorCreator({
  memoize: lruMemoize,
  memoizeOptions: {
    equalityCheck: shallowEqual,
    resultEqualityCheck: shallowEqual,
    maxSize: 10
  },
  argsMemoize: lruMemoize,
  argsMemoizeOptions: {
    equalityCheck: shallowEqual,
    resultEqualityCheck: shallowEqual,
    maxSize: 10
  }
})

const selectTodoIds = createSelectorShallowEqual(
  [state => state.todos],
  todos => todos.map(todo => todo.id)
)
```

  </TabItem>
</Tabs>

{/* END: lruMemoize/usingWithCreateSelectorCreator.ts */}

---

### Api WeakMapMemoize (`docs/api/weakMapMemoize.mdx`)

---
id: weakMapMemoize
title: weakMapMemoize
sidebar_label: weakMapMemoize
hide_title: true
description: 'weakMapMemoize'
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

# `weakMapMemoize`

[`lruMemoize`](./lruMemoize.mdx) has to be explicitly configured to have a cache
size larger than 1, and uses an LRU cache internally.

`weakMapMemoize` creates a tree of [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)-based cache nodes based on the identity of the arguments it's been called with (in this case, the extracted values from your input selectors). **This allows `weakMapMemoize` to have an effectively infinite cache size**. Cache results will be kept in memory as long as references to the arguments still exist, and then cleared out as the arguments are garbage-collected.

:::info Default since v5.0.0

Since v5.0.0, `weakMapMemoize` is the **default** memoization function used by [`createSelector`](./createSelector.mdx) for both `memoize` and `argsMemoize`. In v4.x the default was `lruMemoize` (previously named `defaultMemoize`) with a cache size of **1**.

This means you generally **do not** need to pass `memoize: weakMapMemoize` or `argsMemoize: weakMapMemoize` yourself. The examples on this page pass them explicitly only to illustrate the behavior — a plain `createSelector(...)` call already uses `weakMapMemoize`.

:::

## API Reference

### Parameters

| Name                          | Description                                                                                                                                                                                              |
| :---------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `func`                        | The function to be memoized.                                                                                                                                                                             |
| `options.resultEqualityCheck` | Optional. Compares a newly computed result against the previous one. If they compare equal, the previous result is returned instead, preserving reference equality for downstream consumers.             |
| `options.maxSize`             | Optional. Bounds how many results keyed by primitive arguments are retained. Available since 5.3.0. See [Bounding cache size with `maxSize`](#bounding-cache-size-with-maxsize) below for the semantics. |

### Returns

A memoized function with a `.clearCache()` method attached.

### Type Parameters

| Name   | Description                                |
| :----- | :----------------------------------------- |
| `Func` | The type of the function that is memoized. |

## Usage Guide

### Design Tradeoffs

- Pros:

  - It has an effectively infinite cache size, but you have no control over
    how long values are kept in cache as it's based on garbage collection and [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)s.

- Cons:
  - There's currently no way to alter the argument comparisons. They're based on [strict reference equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality).
  - Garbage collection only frees results keyed by **object or function** arguments. Results keyed by **primitive** arguments (strings, numbers, booleans) are held strongly, and are only released by calling `.clearCache()`. A selector that keeps seeing new primitive values in the same argument position — ids, offsets, timestamps — grows its cache without bound. In development mode, the [`cacheSizeCheck`](./development-only-checks#cachesizecheck) warns when a single argument position passes 1,000 distinct primitive values. As of 5.3.0, the [`maxSize` option](#bounding-cache-size-with-maxsize) bounds this growth.

### Use Cases

- This memoizer is likely best used for cases where you need to call the
  same selector instance with many different arguments, such as a single
  selector instance that is used in a list item component and called with
  item IDs like:

```ts
useSelector(state => selectSomeData(state, id))
```

Prior to `weakMapMemoize`, you had this problem:

{/* START: weakMapMemoize/cacheSizeProblem.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="weakMapMemoize/cacheSizeProblem.ts"
import { createSelector } from 'reselect'

export interface RootState {
  items: { id: number; category: string; name: string }[]
}

const state: RootState = {
  items: [
    { id: 1, category: 'Electronics', name: 'Wireless Headphones' },
    { id: 2, category: 'Books', name: 'The Great Gatsby' },
    { id: 3, category: 'Home Appliances', name: 'Blender' },
    { id: 4, category: 'Stationery', name: 'Sticky Notes' }
  ]
}

const selectItemsByCategory = createSelector(
  [
    (state: RootState) => state.items,
    (state: RootState, category: string) => category
  ],
  (items, category) => items.filter(item => item.category === category)
)

selectItemsByCategory(state, 'Electronics') // Selector runs
selectItemsByCategory(state, 'Electronics')
selectItemsByCategory(state, 'Stationery') // Selector runs
selectItemsByCategory(state, 'Electronics') // Selector runs again!
```

  </TabItem>
  <TabItem value='js'>

```js title="weakMapMemoize/cacheSizeProblem.js"
import { createSelector } from 'reselect'

const state = {
  items: [
    { id: 1, category: 'Electronics', name: 'Wireless Headphones' },
    { id: 2, category: 'Books', name: 'The Great Gatsby' },
    { id: 3, category: 'Home Appliances', name: 'Blender' },
    { id: 4, category: 'Stationery', name: 'Sticky Notes' }
  ]
}

const selectItemsByCategory = createSelector(
  [state => state.items, (state, category) => category],
  (items, category) => items.filter(item => item.category === category)
)

selectItemsByCategory(state, 'Electronics') // Selector runs
selectItemsByCategory(state, 'Electronics')
selectItemsByCategory(state, 'Stationery') // Selector runs
selectItemsByCategory(state, 'Electronics') // Selector runs again!
```

  </TabItem>
</Tabs>

{/* END: weakMapMemoize/cacheSizeProblem.ts */}

Before you could solve this in a number of different ways:

1. Set the `maxSize` with [`lruMemoize`](./lruMemoize.mdx):

{/* START: weakMapMemoize/setMaxSize.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="weakMapMemoize/setMaxSize.ts"
import { createSelector, lruMemoize } from 'reselect'
import type { RootState } from './cacheSizeProblem'

const selectItemsByCategory = createSelector(
  [
    (state: RootState) => state.items,
    (state: RootState, category: string) => category
  ],
  (items, category) => items.filter(item => item.category === category),
  {
    memoize: lruMemoize,
    memoizeOptions: {
      maxSize: 10
    }
  }
)
```

  </TabItem>
  <TabItem value='js'>

```js title="weakMapMemoize/setMaxSize.js"
import { createSelector, lruMemoize } from 'reselect'

const selectItemsByCategory = createSelector(
  [state => state.items, (state, category) => category],
  (items, category) => items.filter(item => item.category === category),
  {
    memoize: lruMemoize,
    memoizeOptions: {
      maxSize: 10
    }
  }
)
```

  </TabItem>
</Tabs>

{/* END: weakMapMemoize/setMaxSize.ts */}

But this required having to know the cache size ahead of time.

2. Create unique selector instances using [`useMemo`](https://react.dev/reference/react/useMemo).

{/* START: weakMapMemoize/withUseMemo.tsx */}

<Tabs
  groupId='language'
  defaultValue='tsx'
  values={[
    {label: 'TypeScript', value: 'tsx'},
    {label: 'JavaScript', value: 'jsx'},
  ]}>
  <TabItem value='tsx'>

```tsx title="weakMapMemoize/withUseMemo.tsx"
import type { FC } from 'react'
import { useMemo } from 'react'
import { useSelector } from 'react-redux'
import { createSelector } from 'reselect'
import type { RootState } from './cacheSizeProblem'

const makeSelectItemsByCategory = (category: string) =>
  createSelector([(state: RootState) => state.items], items =>
    items.filter(item => item.category === category)
  )

interface Props {
  category: string
}

const MyComponent: FC<Props> = ({ category }) => {
  const selectItemsByCategory = useMemo(
    () => makeSelectItemsByCategory(category),
    [category]
  )

  const itemsByCategory = useSelector(selectItemsByCategory)

  return (
    <div>
      {itemsByCategory.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  )
}
```

  </TabItem>
  <TabItem value='jsx'>

```jsx title="weakMapMemoize/withUseMemo.jsx"
import { useMemo } from 'react'
import { useSelector } from 'react-redux'
import { createSelector } from 'reselect'

const makeSelectItemsByCategory = category =>
  createSelector([state => state.items], items =>
    items.filter(item => item.category === category)
  )

const MyComponent = ({ category }) => {
  const selectItemsByCategory = useMemo(
    () => makeSelectItemsByCategory(category),
    [category]
  )

  const itemsByCategory = useSelector(selectItemsByCategory)

  return (
    <div>
      {itemsByCategory.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  )
}
```

  </TabItem>
</Tabs>

{/* END: weakMapMemoize/withUseMemo.tsx */}

3. Use [Re-reselect](https://github.com/toomuchdesign/re-reselect):

```ts
import { createCachedSelector } from 're-reselect'

const selectItemsByCategory = createCachedSelector(
  [
    (state: RootState) => state.items,
    (state: RootState, category: string) => category
  ],
  (items, category) => items.filter(item => item.category === category)
)((state: RootState, category: string) => category)
```

Starting in 5.0.0, you can eliminate this problem using `weakMapMemoize`.

{/* START: weakMapMemoize/cacheSizeSolution.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="weakMapMemoize/cacheSizeSolution.ts"
import { createSelector, weakMapMemoize } from 'reselect'
import type { RootState } from './cacheSizeProblem'

const state: RootState = {
  items: [
    { id: 1, category: 'Electronics', name: 'Wireless Headphones' },
    { id: 2, category: 'Books', name: 'The Great Gatsby' },
    { id: 3, category: 'Home Appliances', name: 'Blender' },
    { id: 4, category: 'Stationery', name: 'Sticky Notes' }
  ]
}

const selectItemsByCategory = createSelector(
  [
    (state: RootState) => state.items,
    (state: RootState, category: string) => category
  ],
  (items, category) => items.filter(item => item.category === category),
  {
    memoize: weakMapMemoize,
    argsMemoize: weakMapMemoize
  }
)

selectItemsByCategory(state, 'Electronics') // Selector runs
selectItemsByCategory(state, 'Electronics') // Cached
selectItemsByCategory(state, 'Stationery') // Selector runs
selectItemsByCategory(state, 'Electronics') // Still cached!
```

  </TabItem>
  <TabItem value='js'>

```js title="weakMapMemoize/cacheSizeSolution.js"
import { createSelector, weakMapMemoize } from 'reselect'

const state = {
  items: [
    { id: 1, category: 'Electronics', name: 'Wireless Headphones' },
    { id: 2, category: 'Books', name: 'The Great Gatsby' },
    { id: 3, category: 'Home Appliances', name: 'Blender' },
    { id: 4, category: 'Stationery', name: 'Sticky Notes' }
  ]
}

const selectItemsByCategory = createSelector(
  [state => state.items, (state, category) => category],
  (items, category) => items.filter(item => item.category === category),
  {
    memoize: weakMapMemoize,
    argsMemoize: weakMapMemoize
  }
)

selectItemsByCategory(state, 'Electronics') // Selector runs
selectItemsByCategory(state, 'Electronics') // Cached
selectItemsByCategory(state, 'Stationery') // Selector runs
selectItemsByCategory(state, 'Electronics') // Still cached!
```

  </TabItem>
</Tabs>

{/* END: weakMapMemoize/cacheSizeSolution.ts */}

This solves the problem of having to know and set the cache size prior to creating a memoized selector. Because `weakMapMemoize` essentially provides a dynamic cache size out of the box.

### Bounding cache size with `maxSize`

The infinite cache size eliminates earlier common pain points around reusing selector instances with varying arguments, which often required cumbersome workarounds like creating a unique selector instance per component instance. Each separate argument combination gets cached, and the code is simpler.

The tradeoff is that an "infinite cache size" can easily become a memory leak depending on arguments and usage patterns. Results keyed by object arguments are freed by garbage collection, but results keyed by **primitive** arguments are held strongly until you call `.clearCache()` (see [Design Tradeoffs](#design-tradeoffs) above). A selector that keeps seeing new primitive values in the same argument position — ids, offsets, timestamps, page numbers — grows its cache without bound.

As of 5.3.0, `weakMapMemoize` accepts a `maxSize` option that bounds this growth:

```ts no-emit
import { weakMapMemoize } from 'reselect'

const getVisibleItems = weakMapMemoize(
  (items: Item[], from: number, to: number) => items.slice(from, to),
  { maxSize: 100 }
)
```

This is implemented using a "generational" approach, rather than the LRU approach used by `lruMemoize`:

- Only results keyed by primitive arguments count toward `maxSize`. Results keyed by objects or functions are already released by garbage collection.
- After `maxSize` new results have been cached, the whole cache is demoted to a "previous generation", and later results build up a fresh cache. When the fresh cache fills up in turn, the previous generation is dropped in one step.
- A call that finds its result in the previous generation promotes that result into the current one, so entries that keep getting used keep surviving the flips.
- Total retention is therefore bounded at roughly `2 * maxSize` results, and eviction happens in batches rather than one entry at a time. This is by design: it keeps the per-call bookkeeping near zero, and there is **no cost at all when `maxSize` is not passed**.

If you need an exact bound with per-entry LRU eviction order, use `lruMemoize` instead — the tradeoff is that its `maxSize` is exact but its bookkeeping runs on every call.

:::warning Bounding a `createSelector` selector requires both options

[`createSelector`](./createSelector.mdx) memoizes at two levels: `argsMemoize` caches by
the selector's call arguments, and `memoize` caches by the input selector
results. If you only set `memoizeOptions: {maxSize}`, the args cache still grows
without bound — and because it sits in front, it returns cached results before
the bounded cache is ever consulted. Pass `maxSize` in **both** options:

```ts no-emit
const selectVisibleItems = createSelector(
  [
    (state: RootState) => state.items,
    (state: RootState, from: number) => from,
    (state: RootState, from: number, to: number) => to
  ],
  (items, from, to) => items.slice(from, to),
  {
    memoizeOptions: { maxSize: 100 },
    argsMemoizeOptions: { maxSize: 100 }
  }
)
```

Since `weakMapMemoize` is the default for both levels, no `memoize` or `argsMemoize` fields are needed — the options objects configure the defaults.

:::

In development mode, the [`cacheSizeCheck`](./development-only-checks#cachesizecheck) warns when a selector shows the unbounded-growth pattern, which is a good signal that a particular selector would benefit from `maxSize`.

### Keeping extra arguments away from unary input selectors

When a `createSelector` selector is called, every input selector receives _all_ of the call's arguments — including input selectors that only use the first one. If such an input selector is itself a memoized selector, its cache is still keyed by the full argument list, so every distinct value of the extra argument creates a separate cache entry for it.

The results stay correct, and result functions do not rerun. But each of those cache entries is checked independently: when the state updates, a selector called with `N` distinct ids re-runs its input selectors `N` times instead of once. In a list where every item calls `useSelector(state => selectSomeData(state, id))` and the state updates frequently, that per-update cost grows with the size of the list. The extra cache entries also hold `N` copies of the same result. A telltale sign is `dependencyRecomputations()` on the inner selector increasing by the number of list items on every state update, rather than by 1.

If an expensive input selector only depends on the state, wrap it so the extra arguments never reach it:

```ts no-emit
const selectSomeData = createSelector(
  [
    // Not `selectHeavyComputation` directly: this keeps `id` out of its cache key
    (state: RootState) => selectHeavyComputation(state),
    (state: RootState, id: string) => id
  ],
  (heavyResult, id) => heavyResult[id]
)
```

### Examples

#### Using `weakMapMemoize` with `createSelector`

{/* START: weakMapMemoize/usingWithCreateSelector.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="weakMapMemoize/usingWithCreateSelector.ts"
import { createSelector, weakMapMemoize } from 'reselect'
import type { RootState } from './cacheSizeProblem'

const state: RootState = {
  items: [
    { id: 1, category: 'Electronics', name: 'Wireless Headphones' },
    { id: 2, category: 'Books', name: 'The Great Gatsby' },
    { id: 3, category: 'Home Appliances', name: 'Blender' },
    { id: 4, category: 'Stationery', name: 'Sticky Notes' }
  ]
}

const selectItemsByCategory = createSelector(
  [
    (state: RootState) => state.items,
    (state: RootState, category: string) => category
  ],
  (items, category) => items.filter(item => item.category === category),
  {
    memoize: weakMapMemoize,
    argsMemoize: weakMapMemoize
  }
)

selectItemsByCategory(state, 'Electronics') // Selector runs
selectItemsByCategory(state, 'Electronics')
selectItemsByCategory(state, 'Stationery') // Selector runs
selectItemsByCategory(state, 'Electronics')
```

  </TabItem>
  <TabItem value='js'>

```js title="weakMapMemoize/usingWithCreateSelector.js"
import { createSelector, weakMapMemoize } from 'reselect'

const state = {
  items: [
    { id: 1, category: 'Electronics', name: 'Wireless Headphones' },
    { id: 2, category: 'Books', name: 'The Great Gatsby' },
    { id: 3, category: 'Home Appliances', name: 'Blender' },
    { id: 4, category: 'Stationery', name: 'Sticky Notes' }
  ]
}

const selectItemsByCategory = createSelector(
  [state => state.items, (state, category) => category],
  (items, category) => items.filter(item => item.category === category),
  {
    memoize: weakMapMemoize,
    argsMemoize: weakMapMemoize
  }
)

selectItemsByCategory(state, 'Electronics') // Selector runs
selectItemsByCategory(state, 'Electronics')
selectItemsByCategory(state, 'Stationery') // Selector runs
selectItemsByCategory(state, 'Electronics')
```

  </TabItem>
</Tabs>

{/* END: weakMapMemoize/usingWithCreateSelector.ts */}

#### Using `weakMapMemoize` with `createSelectorCreator`

{/* START: weakMapMemoize/usingWithCreateSelectorCreator.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="weakMapMemoize/usingWithCreateSelectorCreator.ts"
import { createSelectorCreator, weakMapMemoize } from 'reselect'
import type { RootState } from './cacheSizeProblem'

const state: RootState = {
  items: [
    { id: 1, category: 'Electronics', name: 'Wireless Headphones' },
    { id: 2, category: 'Books', name: 'The Great Gatsby' },
    { id: 3, category: 'Home Appliances', name: 'Blender' },
    { id: 4, category: 'Stationery', name: 'Sticky Notes' }
  ]
}

const createSelectorWeakMap = createSelectorCreator({
  memoize: weakMapMemoize,
  argsMemoize: weakMapMemoize
})

const selectItemsByCategory = createSelectorWeakMap(
  [
    (state: RootState) => state.items,
    (state: RootState, category: string) => category
  ],
  (items, category) => items.filter(item => item.category === category)
)

selectItemsByCategory(state, 'Electronics') // Selector runs
selectItemsByCategory(state, 'Electronics')
selectItemsByCategory(state, 'Stationery') // Selector runs
selectItemsByCategory(state, 'Electronics')
```

  </TabItem>
  <TabItem value='js'>

```js title="weakMapMemoize/usingWithCreateSelectorCreator.js"
import { createSelectorCreator, weakMapMemoize } from 'reselect'

const state = {
  items: [
    { id: 1, category: 'Electronics', name: 'Wireless Headphones' },
    { id: 2, category: 'Books', name: 'The Great Gatsby' },
    { id: 3, category: 'Home Appliances', name: 'Blender' },
    { id: 4, category: 'Stationery', name: 'Sticky Notes' }
  ]
}

const createSelectorWeakMap = createSelectorCreator({
  memoize: weakMapMemoize,
  argsMemoize: weakMapMemoize
})

const selectItemsByCategory = createSelectorWeakMap(
  [state => state.items, (state, category) => category],
  (items, category) => items.filter(item => item.category === category)
)

selectItemsByCategory(state, 'Electronics') // Selector runs
selectItemsByCategory(state, 'Electronics')
selectItemsByCategory(state, 'Stationery') // Selector runs
selectItemsByCategory(state, 'Electronics')
```

  </TabItem>
</Tabs>

{/* END: weakMapMemoize/usingWithCreateSelectorCreator.ts */}

---

### Examples Tsconfig.Json (`docs/examples/tsconfig.json`)

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "allowUnusedLabels": true,
    "isolatedModules": true,
    "removeComments": false,
    "checkJs": true,
    "outDir": "dist",
    "strict": true,
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "allowJs": true,
    "jsx": "preserve",
    "noErrorTruncation": true,
    "forceConsistentCasingInFileNames": true,
    "experimentalDecorators": true,
    "rootDir": "../..",
    "paths": {
      "reselect": ["../../src/index"], // @remap-prod-remove-line
      "@internal/*": ["../../src/*"],
      "createStructuredSelector/*": ["./createStructuredSelector/*"]
    }
  },
  "include": ["**/*.ts", "**/*.tsx"]
}

---

### Introduction How Does Reselect Work (`docs/introduction/how-does-reselect-work.mdx`)

---
id: how-does-reselect-work
title: How Does Reselect Work?
sidebar_label: How Does Reselect Work?
hide_title: true
description: 'How Does Reselect Work?'
---

# How Does Reselect Work?

Reselect, at its core, is a library for creating memoized selectors in JavaScript applications. Its primary role is to efficiently compute derived data based on provided inputs. A key aspect of Reselect's internal mechanism is how it orchestrates the flow of arguments from the final selector to its constituent [input selectors](./getting-started.mdx#input-selectors).

```ts
const finalSelector = (...args) => {
  const extractedValues = inputSelectors.map(inputSelector =>
    inputSelector(...args)
  )
  return resultFunc(...extractedValues)
}
```

In this pattern, the `finalSelector` is composed of several input selectors, **all receiving the same arguments as the final selector**. Each input selector processes its part of the data, and the results are then combined and further processed by the [result function](./getting-started.mdx#result-function). Understanding this argument flow is crucial for appreciating how Reselect optimizes data computation and minimizes unnecessary recalculations.

## Cascading Memoization

Reselect uses a two-stage "cascading" approach to memoizing functions:

The way Reselect works can be broken down into multiple parts:

1. **Initial Run**: On the first call, Reselect runs all the [input selectors](./getting-started.mdx#input-selectors), gathers their results, and passes them to the [result function](./getting-started.mdx#result-function).

2. **Subsequent Runs**: For subsequent calls, Reselect performs two levels of checks:

   - **First Level**: It compares the current arguments with the previous ones (done by `argsMemoize`).

     - If they're the same, it returns the cached result without running the input selectors or the result function.

     - If they differ, it proceeds ("cascades") to the second level.

   - **Second Level**: It runs the input selectors and compares their current results with the previous ones (done by `memoize`).
     :::note

     If any one of the input selectors return a different result, all input selectors will recalculate.

     :::

     - If the results are the same, it returns the cached result without running the result function.
     - If the results differ, it runs the result function.

This behavior is what we call **_Cascading Memoization_**.

### Reselect Vs Standard Memoization

#### Standard Memoization



_Standard memoization only compares arguments. If they're the same, it returns the cached result._

#### Memoization with Reselect



_Reselect adds a second layer of checks with the input selectors. This is crucial in [Redux](/) applications where state references change frequently._

A normal [memoization](https://en.wikipedia.org/wiki/Memoization) function will compare the arguments, and if they are the same as last time, it will skip running the function and return the cached result. However, Reselect enhances this by introducing a second tier of checks via its input selectors. It's possible that the arguments passed to these input selectors may change, yet their results remain the same. When this occurs, Reselect avoids re-executing the result function, and returns the cached result.

This feature becomes crucial in Redux applications, where the `state` changes its reference anytime an `action` is dispatched.

:::note

The input selectors take the same arguments as the [output selector](./getting-started.mdx#output-selector).

:::

## Why Reselect Is Often Used With Redux

While Reselect can be used independently from Redux, it is a standard tool used in most Redux applications to help optimize calculations and UI updates:

Imagine you have a selector like this:

```ts
const selectCompletedTodos = (state: RootState) =>
  state.todos.filter(todo => todo.completed === true)
```

So you decide to memoize it:

```ts
const selectCompletedTodos = someMemoizeFunction((state: RootState) =>
  state.todos.filter(todo => todo.completed === true)
)
```

Then you update `state.alerts`:

```ts
store.dispatch(toggleRead(0))
```

Now when you call `selectCompletedTodos`, it re-runs, because we have effectively broken memoization.

```ts
selectCompletedTodos(store.getState())
// Will not run, and the cached result will be returned.
selectCompletedTodos(store.getState())
store.dispatch(toggleRead(0))
// It recalculates.
selectCompletedTodos(store.getState())
```

But why? `selectCompletedTodos` only needs to access `state.todos`, and has nothing to do with `state.alerts`, so why have we broken memoization? Well that's because in [Redux](/) anytime you make a change to the root `state`, it gets shallowly updated, which means its reference changes, therefore a normal memoization function will always fail the comparison check on the arguments.

But with Reselect, we can do something like this:

```ts
const selectCompletedTodos = createSelector(
  [(state: RootState) => state.todos],
  todos => todos.filter(todo => todo.completed === true)
)
```

And now we have achieved memoization:

```ts
selectCompletedTodos(store.getState())
// Will not run, and the cached result will be returned.
selectCompletedTodos(store.getState())
store.dispatch(toggleRead(0))
// The `input selectors` will run, but the `result function` is
// skipped and the cached result will be returned.
selectCompletedTodos(store.getState())
```

Even when the overall `state` changes, Reselect ensures efficient memoization through its unique approach. The [result function](./getting-started.mdx#result-function) doesn't re-run if the relevant part of the `state` (in this case `state.todos`), remains unchanged. This is due to Reselect's [Cascading Memoization](#cascading-memoization). The first layer checks the entire `state`, and the second layer checks the results of the [input selectors](./getting-started.mdx#input-selectors). If the first layer fails (due to a change in the overall `state`) but the second layer succeeds (because `state.todos` is unchanged), Reselect skips recalculating the result function. This dual-check mechanism makes Reselect particularly effective in Redux applications, ensuring computations are only done when truly necessary.

---

---

### Introduction V5 Summary (`docs/introduction/v5-summary.mdx`)

---
id: v5-summary
title: What's New in 5.0.0?
sidebar_label: What's New in 5.0.0?
hide_title: true
description: What's New in 5.0.0?
---

# What's New in 5.0.0?

Version 5.0.0 introduces several new features and improvements:

## Customization Enhancements

- Added the ability to pass an options object to [`createSelectorCreator`](../api/createSelectorCreator.mdx), allowing for customized `memoize` and `argsMemoize` functions, alongside their respective options (`memoizeOptions` and `argsMemoizeOptions`).
- The [`createSelector`](../api/createSelector.mdx) function now supports direct customization of `memoize` and `argsMemoize` within its options object.

## Memoization Functions

- Introduced new experimental memoization functions: `weakMapMemoize` and `unstable_autotrackMemoize`. (`unstable_autotrackMemoize` was later removed in 5.3.0.)
- Incorporated `memoize` and `argsMemoize` into the [output selector fields](../api/createSelector.mdx#output-selector-fields) for debugging purposes.

## TypeScript Support and Performance

- Discontinued support for TypeScript versions below 4.7, aligning with modern TypeScript features.
- Significantly improved TypeScript performance for nesting [output selectors](./getting-started.mdx#output-selector). The nesting limit has increased from approximately 8 to around 30 output selectors, greatly reducing the occurrence of the infamous `Type instantiation is excessively deep and possibly infinite` error.

## Selector API Enhancements

- Removed the second overload of [`createStructuredSelector`](../api/createStructuredSelector.mdx) due to its susceptibility to runtime errors.

## Additional Functionalities

- Added `dependencyRecomputations` and `resetDependencyRecomputations` to the [output selector fields](../api/createSelector.mdx#output-selector-fields). These additions provide greater control and insight over [input selectors](./getting-started.mdx#input-selectors), complementing the new `argsMemoize` API.
- Introduced `inputStabilityCheck`, a development tool that runs the input selectors twice using the same arguments and triggers a warning If they return differing results for the same call.
- Introduced `identityFunctionCheck`, a development tool that checks to see if the [result function](./getting-started.mdx#result-function) is an [identity function](https://en.wikipedia.org/wiki/Identity_function) .

These updates aim to enhance flexibility, performance, and developer experience. For detailed usage and examples, refer to the updated documentation sections for each feature.

## Breaking Changes

- Switched the default memoization function used by `createSelector` to `weakMapMemoize`.
- Renamed `defaultMemoize` to `lruMemoize` as it is no longer the default memoization function passed to `createSelector`.
- Renamed `defaultEqualityCheck` to `referenceEqualityCheck`.
- Renamed `DefaultMemoizeOptions` to `LruMemoizeOptions`.
- Removed `ParametricSelector` and `OutputParametricSelector` types. Their functionalities are now integrated into `Selector` and `OutputSelector` respectively, which inherently support additional parameters.

---

### Usage Best Practices (`docs/usage/best-practices.mdx`)

---
id: best-practices
title: Best Practices and Common Mistakes
sidebar_label: Best Practices and Common Mistakes
hide_title: true
description: Best Practices and Common Mistakes
---

import Link from '@docusaurus/Link'

# Best Practices and Common Mistakes

This page covers how to get the most out of Reselect's memoization, and the mistakes that defeat it. For the broader question of how selectors fit into a Redux application, see the Redux docs page on [Deriving Data with Selectors](/usage/deriving-data-selectors).

## Best Practices

There are a few details that will help you skip running as many functions as possible and get the best possible performance out of Reselect:

- Due to the [cascading memoization](../introduction/how-does-reselect-work.mdx#cascading-memoization) in Reselect, The first layer of checks is upon the arguments that are passed to the [output selector](../introduction/getting-started.mdx#output-selector), therefore it's best to maintain the same reference for the arguments as much as possible.
- In [Redux](/), your state will change reference when updated. But it's best to keep the additional arguments as simple as possible, you can pass in objects or array as long as their reference does not change. Or you can pass in primitives like numbers for ids.
- Keep your [input selectors](../introduction/getting-started.mdx#input-selectors) as simple as possible. It's best if they mostly consist of field accessors like `state => state.todos` or argument providers like `(state, id) => id`. You should not be doing any sort of calculation inside input selectors, and you should definitely not be returning an object or array with a new reference each time.
- The [result function](../introduction/getting-started.mdx#result-function) is only re-run as a last resort. So make sure to put any and all calculations inside your result function. That way, Reselect will only run those calculations if all other checks fail.

This:

```ts
// ✔️ This is optimal because we have less calculations in input selectors and more in the result function.
const selectorGood = createSelector(
  [(state: RootState) => state.todos],
  todos => someExpensiveComputation(todos)
)
```

Is preferable to this:

```ts
// ❌ This is not optimal!
const selectorBad = createSelector(
  [(state: RootState) => someExpensiveComputation(state.todos)],
  someOtherCalculation
)
```

## Common Mistakes

A somewhat common mistake is to write an [input selector](../introduction/getting-started.mdx#input-selectors) that extracts a value or does some derivation, and a [result function](../introduction/getting-started.mdx#result-function) that just returns its result:

```ts
// ❌ BROKEN: this will not memoize correctly, and does nothing useful!
const brokenSelector = createSelector(
  [(state: RootState) => state.todos],
  todos => todos
)
```

Any result function that just returns its inputs is incorrect! The result function should always have the transformation logic.

Similarly:

```ts
// ❌ BROKEN: this will not memoize correctly!
const brokenSelector = createSelector(
  [(state: RootState) => state],
  state => state.todos
)
```

Using the whole `state` as an input selector means the input changes on every dispatch, so the result function re-runs every time.

Reselect's [development-only checks](../api/development-only-checks.mdx) catch both of these mistakes in development: the `inputStabilityCheck` warns when an input selector returns a new reference for the same arguments, and the `identityFunctionCheck` warns when a result function returns its input unchanged.

---

### Usage Handling Empty Array Results (`docs/usage/handling-empty-array-results.mdx`)

---
id: handling-empty-array-results
title: Handling Empty Array Results
sidebar_label: Handling Empty Array Results
hide_title: true
description: Handling Empty Array Results
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

# Handling Empty Array Results

To reduce recalculations, use a predefined empty array when `array.filter` or similar methods result in an empty array.

So you can have a pattern like this:

{/* START: handling-empty-array-results/firstPattern.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="handling-empty-array-results/firstPattern.ts"
import { createSelector } from 'reselect'

export interface RootState {
  todos: {
    id: number
    title: string
    description: string
    completed: boolean
  }[]
}

const EMPTY_ARRAY: [] = []

const selectCompletedTodos = createSelector(
  [(state: RootState) => state.todos],
  todos => {
    const completedTodos = todos.filter(todo => todo.completed === true)
    return completedTodos.length === 0 ? EMPTY_ARRAY : completedTodos
  }
)
```

  </TabItem>
  <TabItem value='js'>

```js title="handling-empty-array-results/firstPattern.js"
import { createSelector } from 'reselect'

const EMPTY_ARRAY = []

const selectCompletedTodos = createSelector([state => state.todos], todos => {
  const completedTodos = todos.filter(todo => todo.completed === true)
  return completedTodos.length === 0 ? EMPTY_ARRAY : completedTodos
})
```

  </TabItem>
</Tabs>

{/* END: handling-empty-array-results/firstPattern.ts */}

Or to avoid repetition, you can create a wrapper function and reuse it:

{/* START: handling-empty-array-results/fallbackToEmptyArray.ts */}

<Tabs
  groupId='language'
  defaultValue='ts'
  values={[
    {label: 'TypeScript', value: 'ts'},
    {label: 'JavaScript', value: 'js'},
  ]}>
  <TabItem value='ts'>

```ts title="handling-empty-array-results/fallbackToEmptyArray.ts"
import { createSelector } from 'reselect'
import type { RootState } from './firstPattern'

const EMPTY_ARRAY: [] = []

export const fallbackToEmptyArray = <T>(array: T[]) => {
  return array.length === 0 ? EMPTY_ARRAY : array
}

const selectCompletedTodos = createSelector(
  [(state: RootState) => state.todos],
  todos => {
    return fallbackToEmptyArray(todos.filter(todo => todo.completed === true))
  }
)
```

  </TabItem>
  <TabItem value='js'>

```js title="handling-empty-array-results/fallbackToEmptyArray.js"
import { createSelector } from 'reselect'

const EMPTY_ARRAY = []

export const fallbackToEmptyArray = array => {
  return array.length === 0 ? EMPTY_ARRAY : array
}

const selectCompletedTodos = createSelector([state => state.todos], todos => {
  return fallbackToEmptyArray(todos.filter(todo => todo.completed === true))
})
```

  </TabItem>
</Tabs>

{/* END: handling-empty-array-results/fallbackToEmptyArray.ts */}

This way if the [result function](../introduction/getting-started.mdx#result-function) returns an empty array twice in a row, your component will not re-render due to a stable empty array reference:

```ts
const completedTodos = selectCompletedTodos(store.getState())

store.dispatch(addTodo())

console.log(completedTodos === selectCompletedTodos(store.getState())) //=> true
```

---

--- METRICS ---
- Files Extracted: 18
- Estimated Token Budget: ~34752 tokens
- Canonical Reference: https://codewiki.google/github.com/reduxjs/reselect
