reselect
Version:
Selectors for Redux.
1 lines • 91.3 kB
Source Map (JSON)
{"version":3,"sources":["../src/devModeChecks/setGlobalDevModeChecks.ts","../src/utils.ts","../src/autotrackMemoize/autotracking.ts","../src/autotrackMemoize/tracking.ts","../src/autotrackMemoize/proxy.ts","../src/lruMemoize.ts","../src/autotrackMemoize/autotrackMemoize.ts","../src/weakMapMemoize.ts","../src/createSelectorCreator.ts","../src/createStructuredSelector.ts"],"sourcesContent":["import type { DevModeChecks } from '../types'\r\n\r\n/**\r\n * Global configuration for development mode checks. This specifies the default\r\n * frequency at which each development mode check should be performed.\r\n *\r\n * @since 5.0.0\r\n * @internal\r\n */\r\nexport const globalDevModeChecks: DevModeChecks = {\r\n inputStabilityCheck: 'once',\r\n identityFunctionCheck: 'once'\r\n}\r\n\r\n/**\r\n * Overrides the development mode checks settings for all selectors.\r\n *\r\n * Reselect performs additional checks in development mode to help identify and\r\n * warn about potential issues in selector behavior. This function allows you to\r\n * customize the behavior of these checks across all selectors in your application.\r\n *\r\n * **Note**: This setting can still be overridden per selector inside `createSelector`'s `options` object.\r\n * See {@link https://github.com/reduxjs/reselect#2-per-selector-by-passing-an-identityfunctioncheck-option-directly-to-createselector per-selector-configuration}\r\n * and {@linkcode CreateSelectorOptions.identityFunctionCheck identityFunctionCheck} for more details.\r\n *\r\n * _The development mode checks do not run in production builds._\r\n *\r\n * @param devModeChecks - An object specifying the desired settings for development mode checks. You can provide partial overrides. Unspecified settings will retain their current values.\r\n *\r\n * @example\r\n * ```ts\r\n * import { setGlobalDevModeChecks } from 'reselect'\r\n * import { DevModeChecks } from '../types'\r\n *\r\n * // Run only the first time the selector is called. (default)\r\n * setGlobalDevModeChecks({ inputStabilityCheck: 'once' })\r\n *\r\n * // Run every time the selector is called.\r\n * setGlobalDevModeChecks({ inputStabilityCheck: 'always' })\r\n *\r\n * // Never run the input stability check.\r\n * setGlobalDevModeChecks({ inputStabilityCheck: 'never' })\r\n *\r\n * // Run only the first time the selector is called. (default)\r\n * setGlobalDevModeChecks({ identityFunctionCheck: 'once' })\r\n *\r\n * // Run every time the selector is called.\r\n * setGlobalDevModeChecks({ identityFunctionCheck: 'always' })\r\n *\r\n * // Never run the identity function check.\r\n * setGlobalDevModeChecks({ identityFunctionCheck: 'never' })\r\n * ```\r\n * @see {@link https://reselect.js.org/api/development-only-stability-checks Development-Only Stability Checks}\r\n * @see {@link https://reselect.js.org/api/development-only-stability-checks#1-globally-through-setglobaldevmodechecks global-configuration}\r\n *\r\n * @since 5.0.0\r\n * @public\r\n */\r\nexport const setGlobalDevModeChecks = (\r\n devModeChecks: Partial<DevModeChecks>\r\n) => {\r\n Object.assign(globalDevModeChecks, devModeChecks)\r\n}\r\n","import { runIdentityFunctionCheck } from './devModeChecks/identityFunctionCheck'\r\nimport { runInputStabilityCheck } from './devModeChecks/inputStabilityCheck'\r\nimport { globalDevModeChecks } from './devModeChecks/setGlobalDevModeChecks'\r\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\r\nimport type {\r\n DevModeChecks,\r\n Selector,\r\n SelectorArray,\r\n DevModeChecksExecutionInfo\r\n} from './types'\r\n\r\nexport const NOT_FOUND = /* @__PURE__ */ Symbol('NOT_FOUND')\r\nexport type NOT_FOUND_TYPE = typeof NOT_FOUND\r\n\r\n/**\r\n * Assert that the provided value is a function. If the assertion fails,\r\n * a `TypeError` is thrown with an optional custom error message.\r\n *\r\n * @param func - The value to be checked.\r\n * @param errorMessage - An optional custom error message to use if the assertion fails.\r\n * @throws A `TypeError` if the assertion fails.\r\n */\r\nexport function assertIsFunction<FunctionType extends Function>(\r\n func: unknown,\r\n errorMessage = `expected a function, instead received ${typeof func}`\r\n): asserts func is FunctionType {\r\n if (typeof func !== 'function') {\r\n throw new TypeError(errorMessage)\r\n }\r\n}\r\n\r\n/**\r\n * Assert that the provided value is an object. If the assertion fails,\r\n * a `TypeError` is thrown with an optional custom error message.\r\n *\r\n * @param object - The value to be checked.\r\n * @param errorMessage - An optional custom error message to use if the assertion fails.\r\n * @throws A `TypeError` if the assertion fails.\r\n */\r\nexport function assertIsObject<ObjectType extends Record<string, unknown>>(\r\n object: unknown,\r\n errorMessage = `expected an object, instead received ${typeof object}`\r\n): asserts object is ObjectType {\r\n if (typeof object !== 'object') {\r\n throw new TypeError(errorMessage)\r\n }\r\n}\r\n\r\n/**\r\n * Assert that the provided array is an array of functions. If the assertion fails,\r\n * a `TypeError` is thrown with an optional custom error message.\r\n *\r\n * @param array - The array to be checked.\r\n * @param errorMessage - An optional custom error message to use if the assertion fails.\r\n * @throws A `TypeError` if the assertion fails.\r\n */\r\nexport function assertIsArrayOfFunctions<FunctionType extends Function>(\r\n array: unknown[],\r\n errorMessage = `expected all items to be functions, instead received the following types: `\r\n): asserts array is FunctionType[] {\r\n if (\r\n !array.every((item): item is FunctionType => typeof item === 'function')\r\n ) {\r\n const itemTypes = array\r\n .map(item =>\r\n typeof item === 'function'\r\n ? `function ${item.name || 'unnamed'}()`\r\n : typeof item\r\n )\r\n .join(', ')\r\n throw new TypeError(`${errorMessage}[${itemTypes}]`)\r\n }\r\n}\r\n\r\n/**\r\n * Ensure that the input is an array. If it's already an array, it's returned as is.\r\n * If it's not an array, it will be wrapped in a new array.\r\n *\r\n * @param item - The item to be checked.\r\n * @returns An array containing the input item. If the input is already an array, it's returned without modification.\r\n */\r\nexport const ensureIsArray = (item: unknown) => {\r\n return Array.isArray(item) ? item : [item]\r\n}\r\n\r\n/**\r\n * Extracts the \"dependencies\" / \"input selectors\" from the arguments of `createSelector`.\r\n *\r\n * @param createSelectorArgs - Arguments passed to `createSelector` as an array.\r\n * @returns An array of \"input selectors\" / \"dependencies\".\r\n * @throws A `TypeError` if any of the input selectors is not function.\r\n */\r\nexport function getDependencies(createSelectorArgs: unknown[]) {\r\n const dependencies = Array.isArray(createSelectorArgs[0])\r\n ? createSelectorArgs[0]\r\n : createSelectorArgs\r\n\r\n assertIsArrayOfFunctions<Selector>(\r\n dependencies,\r\n `createSelector expects all input-selectors to be functions, but received the following types: `\r\n )\r\n\r\n return dependencies as SelectorArray\r\n}\r\n\r\n/**\r\n * Runs each input selector and returns their collective results as an array.\r\n *\r\n * @param dependencies - An array of \"dependencies\" or \"input selectors\".\r\n * @param inputSelectorArgs - An array of arguments being passed to the input selectors.\r\n * @returns An array of input selector results.\r\n */\r\nexport function collectInputSelectorResults(\r\n dependencies: SelectorArray,\r\n inputSelectorArgs: unknown[] | IArguments\r\n) {\r\n const inputSelectorResults = []\r\n const { length } = dependencies\r\n for (let i = 0; i < length; i++) {\r\n // @ts-ignore\r\n // apply arguments instead of spreading and mutate a local list of params for performance.\r\n inputSelectorResults.push(dependencies[i].apply(null, inputSelectorArgs))\r\n }\r\n return inputSelectorResults\r\n}\r\n\r\n/**\r\n * Retrieves execution information for development mode checks.\r\n *\r\n * @param devModeChecks - Custom Settings for development mode checks. These settings will override the global defaults.\r\n * @param firstRun - Indicates whether it is the first time the selector has run.\r\n * @returns An object containing the execution information for each development mode check.\r\n */\r\nexport const getDevModeChecksExecutionInfo = (\r\n firstRun: boolean,\r\n devModeChecks: Partial<DevModeChecks>\r\n) => {\r\n const { identityFunctionCheck, inputStabilityCheck } = {\r\n ...globalDevModeChecks,\r\n ...devModeChecks\r\n }\r\n return {\r\n identityFunctionCheck: {\r\n shouldRun:\r\n identityFunctionCheck === 'always' ||\r\n (identityFunctionCheck === 'once' && firstRun),\r\n run: runIdentityFunctionCheck\r\n },\r\n inputStabilityCheck: {\r\n shouldRun:\r\n inputStabilityCheck === 'always' ||\r\n (inputStabilityCheck === 'once' && firstRun),\r\n run: runInputStabilityCheck\r\n }\r\n } satisfies DevModeChecksExecutionInfo\r\n}\r\n","// Original autotracking implementation source:\r\n// - https://gist.github.com/pzuraq/79bf862e0f8cd9521b79c4b6eccdc4f9\r\n// Additional references:\r\n// - https://www.pzuraq.com/blog/how-autotracking-works\r\n// - https://v5.chriskrycho.com/journal/autotracking-elegant-dx-via-cutting-edge-cs/\r\nimport type { EqualityFn } from '../types'\r\nimport { assertIsFunction } from '../utils'\r\n\r\n// The global revision clock. Every time state changes, the clock increments.\r\nexport let $REVISION = 0\r\n\r\n// The current dependency tracker. Whenever we compute a cache, we create a Set\r\n// to track any dependencies that are used while computing. If no cache is\r\n// computing, then the tracker is null.\r\nlet CURRENT_TRACKER: Set<Cell<any> | TrackingCache> | null = null\r\n\r\n// Storage represents a root value in the system - the actual state of our app.\r\nexport class Cell<T> {\r\n revision = $REVISION\r\n\r\n _value: T\r\n _lastValue: T\r\n _isEqual: EqualityFn = tripleEq\r\n\r\n constructor(initialValue: T, isEqual: EqualityFn = tripleEq) {\r\n this._value = this._lastValue = initialValue\r\n this._isEqual = isEqual\r\n }\r\n\r\n // Whenever a storage value is read, it'll add itself to the current tracker if\r\n // one exists, entangling its state with that cache.\r\n get value() {\r\n CURRENT_TRACKER?.add(this)\r\n\r\n return this._value\r\n }\r\n\r\n // Whenever a storage value is updated, we bump the global revision clock,\r\n // assign the revision for this storage to the new value, _and_ we schedule a\r\n // rerender. This is important, and it's what makes autotracking _pull_\r\n // based. We don't actively tell the caches which depend on the storage that\r\n // anything has happened. Instead, we recompute the caches when needed.\r\n set value(newValue) {\r\n if (this.value === newValue) return\r\n\r\n this._value = newValue\r\n this.revision = ++$REVISION\r\n }\r\n}\r\n\r\nfunction tripleEq(a: unknown, b: unknown) {\r\n return a === b\r\n}\r\n\r\n// Caches represent derived state in the system. They are ultimately functions\r\n// that are memoized based on what state they use to produce their output,\r\n// meaning they will only rerun IFF a storage value that could affect the output\r\n// has changed. Otherwise, they'll return the cached value.\r\nexport class TrackingCache {\r\n _cachedValue: any\r\n _cachedRevision = -1\r\n _deps: any[] = []\r\n hits = 0\r\n\r\n fn: () => any\r\n\r\n constructor(fn: () => any) {\r\n this.fn = fn\r\n }\r\n\r\n clear() {\r\n this._cachedValue = undefined\r\n this._cachedRevision = -1\r\n this._deps = []\r\n this.hits = 0\r\n }\r\n\r\n get value() {\r\n // When getting the value for a Cache, first we check all the dependencies of\r\n // the cache to see what their current revision is. If the current revision is\r\n // greater than the cached revision, then something has changed.\r\n if (this.revision > this._cachedRevision) {\r\n const { fn } = this\r\n\r\n // We create a new dependency tracker for this cache. As the cache runs\r\n // its function, any Storage or Cache instances which are used while\r\n // computing will be added to this tracker. In the end, it will be the\r\n // full list of dependencies that this Cache depends on.\r\n const currentTracker = new Set<Cell<any>>()\r\n const prevTracker = CURRENT_TRACKER\r\n\r\n CURRENT_TRACKER = currentTracker\r\n\r\n // try {\r\n this._cachedValue = fn()\r\n // } finally {\r\n CURRENT_TRACKER = prevTracker\r\n this.hits++\r\n this._deps = Array.from(currentTracker)\r\n\r\n // Set the cached revision. This is the current clock count of all the\r\n // dependencies. If any dependency changes, this number will be less\r\n // than the new revision.\r\n this._cachedRevision = this.revision\r\n // }\r\n }\r\n\r\n // If there is a current tracker, it means another Cache is computing and\r\n // using this one, so we add this one to the tracker.\r\n CURRENT_TRACKER?.add(this)\r\n\r\n // Always return the cached value.\r\n return this._cachedValue\r\n }\r\n\r\n get revision() {\r\n // The current revision is the max of all the dependencies' revisions.\r\n return Math.max(...this._deps.map(d => d.revision), 0)\r\n }\r\n}\r\n\r\nexport function getValue<T>(cell: Cell<T>): T {\r\n if (!(cell instanceof Cell)) {\r\n console.warn('Not a valid cell! ', cell)\r\n }\r\n\r\n return cell.value\r\n}\r\n\r\ntype CellValue<T extends Cell<unknown>> = T extends Cell<infer U> ? U : never\r\n\r\nexport function setValue<T extends Cell<unknown>>(\r\n storage: T,\r\n value: CellValue<T>\r\n): void {\r\n if (!(storage instanceof Cell)) {\r\n throw new TypeError(\r\n 'setValue must be passed a tracked store created with `createStorage`.'\r\n )\r\n }\r\n\r\n storage.value = storage._lastValue = value\r\n}\r\n\r\nexport function createCell<T = unknown>(\r\n initialValue: T,\r\n isEqual: EqualityFn = tripleEq\r\n): Cell<T> {\r\n return new Cell(initialValue, isEqual)\r\n}\r\n\r\nexport function createCache<T = unknown>(fn: () => T): TrackingCache {\r\n assertIsFunction(\r\n fn,\r\n 'the first parameter to `createCache` must be a function'\r\n )\r\n\r\n return new TrackingCache(fn)\r\n}\r\n","import type { Cell } from './autotracking'\r\nimport {\r\n getValue as consumeTag,\r\n createCell as createStorage,\r\n setValue\r\n} from './autotracking'\r\n\r\nexport type Tag = Cell<unknown>\r\n\r\nconst neverEq = (a: any, b: any): boolean => false\r\n\r\nexport function createTag(): Tag {\r\n return createStorage(null, neverEq)\r\n}\r\nexport { consumeTag }\r\nexport function dirtyTag(tag: Tag, value: any): void {\r\n setValue(tag, value)\r\n}\r\n\r\nexport interface Node<\r\n T extends Array<unknown> | Record<string, unknown> =\r\n | Array<unknown>\r\n | Record<string, unknown>\r\n> {\r\n collectionTag: Tag | null\r\n tag: Tag | null\r\n tags: Record<string, Tag>\r\n children: Record<string, Node>\r\n proxy: T\r\n value: T\r\n id: number\r\n}\r\n\r\nexport const consumeCollection = (node: Node): void => {\r\n let tag = node.collectionTag\r\n\r\n if (tag === null) {\r\n tag = node.collectionTag = createTag()\r\n }\r\n\r\n consumeTag(tag)\r\n}\r\n\r\nexport const dirtyCollection = (node: Node): void => {\r\n const tag = node.collectionTag\r\n\r\n if (tag !== null) {\r\n dirtyTag(tag, null)\r\n }\r\n}\r\n","// Original source:\r\n// - https://github.com/simonihmig/tracked-redux/blob/master/packages/tracked-redux/src/-private/proxy.ts\r\n\r\nimport type { Node, Tag } from './tracking'\r\nimport {\r\n consumeCollection,\r\n consumeTag,\r\n createTag,\r\n dirtyCollection,\r\n dirtyTag\r\n} from './tracking'\r\n\r\nexport const REDUX_PROXY_LABEL = Symbol()\r\n\r\nlet nextId = 0\r\n\r\nconst proto = Object.getPrototypeOf({})\r\n\r\nclass ObjectTreeNode<T extends Record<string, unknown>> implements Node<T> {\r\n proxy: T = new Proxy(this, objectProxyHandler) as unknown as T\r\n tag = createTag()\r\n tags = {} as Record<string, Tag>\r\n children = {} as Record<string, Node>\r\n collectionTag = null\r\n id = nextId++\r\n\r\n constructor(public value: T) {\r\n this.value = value\r\n this.tag.value = value\r\n }\r\n}\r\n\r\nconst objectProxyHandler = {\r\n get(node: Node, key: string | symbol): unknown {\r\n function calculateResult() {\r\n const { value } = node\r\n\r\n const childValue = Reflect.get(value, key)\r\n\r\n if (typeof key === 'symbol') {\r\n return childValue\r\n }\r\n\r\n if (key in proto) {\r\n return childValue\r\n }\r\n\r\n if (typeof childValue === 'object' && childValue !== null) {\r\n let childNode = node.children[key]\r\n\r\n if (childNode === undefined) {\r\n childNode = node.children[key] = createNode(childValue)\r\n }\r\n\r\n if (childNode.tag) {\r\n consumeTag(childNode.tag)\r\n }\r\n\r\n return childNode.proxy\r\n } else {\r\n let tag = node.tags[key]\r\n\r\n if (tag === undefined) {\r\n tag = node.tags[key] = createTag()\r\n tag.value = childValue\r\n }\r\n\r\n consumeTag(tag)\r\n\r\n return childValue\r\n }\r\n }\r\n const res = calculateResult()\r\n return res\r\n },\r\n\r\n ownKeys(node: Node): ArrayLike<string | symbol> {\r\n consumeCollection(node)\r\n return Reflect.ownKeys(node.value)\r\n },\r\n\r\n getOwnPropertyDescriptor(\r\n node: Node,\r\n prop: string | symbol\r\n ): PropertyDescriptor | undefined {\r\n return Reflect.getOwnPropertyDescriptor(node.value, prop)\r\n },\r\n\r\n has(node: Node, prop: string | symbol): boolean {\r\n return Reflect.has(node.value, prop)\r\n }\r\n}\r\n\r\nclass ArrayTreeNode<T extends Array<unknown>> implements Node<T> {\r\n proxy: T = new Proxy([this], arrayProxyHandler) as unknown as T\r\n tag = createTag()\r\n tags = {}\r\n children = {}\r\n collectionTag = null\r\n id = nextId++\r\n\r\n constructor(public value: T) {\r\n this.value = value\r\n this.tag.value = value\r\n }\r\n}\r\n\r\nconst arrayProxyHandler = {\r\n get([node]: [Node], key: string | symbol): unknown {\r\n if (key === 'length') {\r\n consumeCollection(node)\r\n }\r\n\r\n return objectProxyHandler.get(node, key)\r\n },\r\n\r\n ownKeys([node]: [Node]): ArrayLike<string | symbol> {\r\n return objectProxyHandler.ownKeys(node)\r\n },\r\n\r\n getOwnPropertyDescriptor(\r\n [node]: [Node],\r\n prop: string | symbol\r\n ): PropertyDescriptor | undefined {\r\n return objectProxyHandler.getOwnPropertyDescriptor(node, prop)\r\n },\r\n\r\n has([node]: [Node], prop: string | symbol): boolean {\r\n return objectProxyHandler.has(node, prop)\r\n }\r\n}\r\n\r\nexport function createNode<T extends Array<unknown> | Record<string, unknown>>(\r\n value: T\r\n): Node<T> {\r\n if (Array.isArray(value)) {\r\n return new ArrayTreeNode(value)\r\n }\r\n\r\n return new ObjectTreeNode(value) as Node<T>\r\n}\r\n\r\nconst keysMap = new WeakMap<\r\n Array<unknown> | Record<string, unknown>,\r\n Set<string>\r\n>()\r\n\r\nexport function updateNode<T extends Array<unknown> | Record<string, unknown>>(\r\n node: Node<T>,\r\n newValue: T\r\n): void {\r\n const { value, tags, children } = node\r\n\r\n node.value = newValue\r\n\r\n if (\r\n Array.isArray(value) &&\r\n Array.isArray(newValue) &&\r\n value.length !== newValue.length\r\n ) {\r\n dirtyCollection(node)\r\n } else {\r\n if (value !== newValue) {\r\n let oldKeysSize = 0\r\n let newKeysSize = 0\r\n let anyKeysAdded = false\r\n\r\n for (const _key in value) {\r\n oldKeysSize++\r\n }\r\n\r\n for (const key in newValue) {\r\n newKeysSize++\r\n if (!(key in value)) {\r\n anyKeysAdded = true\r\n break\r\n }\r\n }\r\n\r\n const isDifferent = anyKeysAdded || oldKeysSize !== newKeysSize\r\n\r\n if (isDifferent) {\r\n dirtyCollection(node)\r\n }\r\n }\r\n }\r\n\r\n for (const key in tags) {\r\n const childValue = (value as Record<string, unknown>)[key]\r\n const newChildValue = (newValue as Record<string, unknown>)[key]\r\n\r\n if (childValue !== newChildValue) {\r\n dirtyCollection(node)\r\n dirtyTag(tags[key], newChildValue)\r\n }\r\n\r\n if (typeof newChildValue === 'object' && newChildValue !== null) {\r\n delete tags[key]\r\n }\r\n }\r\n\r\n for (const key in children) {\r\n const childNode = children[key]\r\n const newChildValue = (newValue as Record<string, unknown>)[key]\r\n\r\n const childValue = childNode.value\r\n\r\n if (childValue === newChildValue) {\r\n continue\r\n } else if (typeof newChildValue === 'object' && newChildValue !== null) {\r\n updateNode(childNode, newChildValue as Record<string, unknown>)\r\n } else {\r\n deleteNode(childNode)\r\n delete children[key]\r\n }\r\n }\r\n}\r\n\r\nfunction deleteNode(node: Node): void {\r\n if (node.tag) {\r\n dirtyTag(node.tag, null)\r\n }\r\n dirtyCollection(node)\r\n for (const key in node.tags) {\r\n dirtyTag(node.tags[key], null)\r\n }\r\n for (const key in node.children) {\r\n deleteNode(node.children[key])\r\n }\r\n}\r\n","import type {\r\n AnyFunction,\r\n DefaultMemoizeFields,\r\n EqualityFn,\r\n Simplify\r\n} from './types'\r\n\r\nimport type { NOT_FOUND_TYPE } from './utils'\r\nimport { NOT_FOUND } from './utils'\r\n\r\n// Cache implementation based on Erik Rasmussen's `lru-memoize`:\r\n// https://github.com/erikras/lru-memoize\r\n\r\ninterface Entry {\r\n key: unknown\r\n value: unknown\r\n}\r\n\r\ninterface Cache {\r\n get(key: unknown): unknown | NOT_FOUND_TYPE\r\n put(key: unknown, value: unknown): void\r\n getEntries(): Entry[]\r\n clear(): void\r\n}\r\n\r\nfunction createSingletonCache(equals: EqualityFn): Cache {\r\n let entry: Entry | undefined\r\n return {\r\n get(key: unknown) {\r\n if (entry && equals(entry.key, key)) {\r\n return entry.value\r\n }\r\n\r\n return NOT_FOUND\r\n },\r\n\r\n put(key: unknown, value: unknown) {\r\n entry = { key, value }\r\n },\r\n\r\n getEntries() {\r\n return entry ? [entry] : []\r\n },\r\n\r\n clear() {\r\n entry = undefined\r\n }\r\n }\r\n}\r\n\r\nfunction createLruCache(maxSize: number, equals: EqualityFn): Cache {\r\n let entries: Entry[] = []\r\n\r\n function get(key: unknown) {\r\n const cacheIndex = entries.findIndex(entry => equals(key, entry.key))\r\n\r\n // We found a cached entry\r\n if (cacheIndex > -1) {\r\n const entry = entries[cacheIndex]\r\n\r\n // Cached entry not at top of cache, move it to the top\r\n if (cacheIndex > 0) {\r\n entries.splice(cacheIndex, 1)\r\n entries.unshift(entry)\r\n }\r\n\r\n return entry.value\r\n }\r\n\r\n // No entry found in cache, return sentinel\r\n return NOT_FOUND\r\n }\r\n\r\n function put(key: unknown, value: unknown) {\r\n if (get(key) === NOT_FOUND) {\r\n // TODO Is unshift slow?\r\n entries.unshift({ key, value })\r\n if (entries.length > maxSize) {\r\n entries.pop()\r\n }\r\n }\r\n }\r\n\r\n function getEntries() {\r\n return entries\r\n }\r\n\r\n function clear() {\r\n entries = []\r\n }\r\n\r\n return { get, put, getEntries, clear }\r\n}\r\n\r\n/**\r\n * Runs a simple reference equality check.\r\n * What {@linkcode lruMemoize lruMemoize} uses by default.\r\n *\r\n * **Note**: This function was previously known as `defaultEqualityCheck`.\r\n *\r\n * @public\r\n */\r\nexport const referenceEqualityCheck: EqualityFn = (a, b) => a === b\r\n\r\nexport function createCacheKeyComparator(equalityCheck: EqualityFn) {\r\n return function areArgumentsShallowlyEqual(\r\n prev: unknown[] | IArguments | null,\r\n next: unknown[] | IArguments | null\r\n ): boolean {\r\n if (prev === null || next === null || prev.length !== next.length) {\r\n return false\r\n }\r\n\r\n // Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.\r\n const { length } = prev\r\n for (let i = 0; i < length; i++) {\r\n if (!equalityCheck(prev[i], next[i])) {\r\n return false\r\n }\r\n }\r\n\r\n return true\r\n }\r\n}\r\n\r\n/**\r\n * Options for configuring the behavior of a function memoized with\r\n * LRU (Least Recently Used) caching.\r\n *\r\n * @template Result - The type of the return value of the memoized function.\r\n *\r\n * @public\r\n */\r\nexport interface LruMemoizeOptions<Result = any> {\r\n /**\r\n * Function used to compare the individual arguments of the\r\n * provided calculation function.\r\n *\r\n * @default referenceEqualityCheck\r\n */\r\n equalityCheck?: EqualityFn\r\n\r\n /**\r\n * If provided, used to compare a newly generated output value against\r\n * previous values in the cache. If a match is found,\r\n * the old value is returned. This addresses the common\r\n * ```ts\r\n * todos.map(todo => todo.id)\r\n * ```\r\n * use case, where an update to another field in the original data causes\r\n * a recalculation due to changed references, but the output is still\r\n * effectively the same.\r\n *\r\n * @since 4.1.0\r\n */\r\n resultEqualityCheck?: EqualityFn<Result>\r\n\r\n /**\r\n * The maximum size of the cache used by the selector.\r\n * A size greater than 1 means the selector will use an\r\n * LRU (Least Recently Used) cache, allowing for the caching of multiple\r\n * results based on different sets of arguments.\r\n *\r\n * @default 1\r\n */\r\n maxSize?: number\r\n}\r\n\r\n/**\r\n * Creates a memoized version of a function with an optional\r\n * LRU (Least Recently Used) cache. The memoized function uses a cache to\r\n * store computed values. Depending on the `maxSize` option, it will use\r\n * either a singleton cache (for a single entry) or an\r\n * LRU cache (for multiple entries).\r\n *\r\n * **Note**: This function was previously known as `defaultMemoize`.\r\n *\r\n * @param func - The function to be memoized.\r\n * @param equalityCheckOrOptions - Either an equality check function or an options object.\r\n * @returns A memoized function with a `.clearCache()` method attached.\r\n *\r\n * @template Func - The type of the function that is memoized.\r\n *\r\n * @see {@link https://reselect.js.org/api/lruMemoize `lruMemoize`}\r\n *\r\n * @public\r\n */\r\nexport function lruMemoize<Func extends AnyFunction>(\r\n func: Func,\r\n equalityCheckOrOptions?: EqualityFn | LruMemoizeOptions<ReturnType<Func>>\r\n) {\r\n const providedOptions =\r\n typeof equalityCheckOrOptions === 'object'\r\n ? equalityCheckOrOptions\r\n : { equalityCheck: equalityCheckOrOptions }\r\n\r\n const {\r\n equalityCheck = referenceEqualityCheck,\r\n maxSize = 1,\r\n resultEqualityCheck\r\n } = providedOptions\r\n\r\n const comparator = createCacheKeyComparator(equalityCheck)\r\n\r\n let resultsCount = 0\r\n\r\n const cache =\r\n maxSize <= 1\r\n ? createSingletonCache(comparator)\r\n : createLruCache(maxSize, comparator)\r\n\r\n function memoized() {\r\n let value = cache.get(arguments) as ReturnType<Func>\r\n if (value === NOT_FOUND) {\r\n // apply arguments instead of spreading for performance.\r\n // @ts-ignore\r\n value = func.apply(null, arguments) as ReturnType<Func>\r\n resultsCount++\r\n\r\n if (resultEqualityCheck) {\r\n const entries = cache.getEntries()\r\n const matchingEntry = entries.find(entry =>\r\n resultEqualityCheck(entry.value as ReturnType<Func>, value)\r\n )\r\n\r\n if (matchingEntry) {\r\n value = matchingEntry.value as ReturnType<Func>\r\n resultsCount !== 0 && resultsCount--\r\n }\r\n }\r\n\r\n cache.put(arguments, value)\r\n }\r\n return value\r\n }\r\n\r\n memoized.clearCache = () => {\r\n cache.clear()\r\n memoized.resetResultsCount()\r\n }\r\n\r\n memoized.resultsCount = () => resultsCount\r\n\r\n memoized.resetResultsCount = () => {\r\n resultsCount = 0\r\n }\r\n\r\n return memoized as Func & Simplify<DefaultMemoizeFields>\r\n}\r\n","import { createNode, updateNode } from './proxy'\r\nimport type { Node } from './tracking'\r\n\r\nimport { createCacheKeyComparator, referenceEqualityCheck } from '../lruMemoize'\r\nimport type { AnyFunction, DefaultMemoizeFields, Simplify } from '../types'\r\nimport { createCache } from './autotracking'\r\n\r\n/**\r\n * Uses an \"auto-tracking\" approach inspired by the work of the Ember Glimmer team.\r\n * It uses a Proxy to wrap arguments and track accesses to nested fields\r\n * in your selector on first read. Later, when the selector is called with\r\n * new arguments, it identifies which accessed fields have changed and\r\n * only recalculates the result if one or more of those accessed fields have changed.\r\n * This allows it to be more precise than the shallow equality checks in `lruMemoize`.\r\n *\r\n * __Design Tradeoffs for `autotrackMemoize`:__\r\n * - Pros:\r\n * - It is likely to avoid excess calculations and recalculate fewer times than `lruMemoize` will,\r\n * which may also result in fewer component re-renders.\r\n * - Cons:\r\n * - It only has a cache size of 1.\r\n * - It is slower than `lruMemoize`, because it has to do more work. (How much slower is dependent on the number of accessed fields in a selector, number of calls, frequency of input changes, etc)\r\n * - It can have some unexpected behavior. Because it tracks nested field accesses,\r\n * cases where you don't access a field will not recalculate properly.\r\n * For example, a badly-written selector like:\r\n * ```ts\r\n * createSelector([state => state.todos], todos => todos)\r\n * ```\r\n * that just immediately returns the extracted value will never update, because it doesn't see any field accesses to check.\r\n *\r\n * __Use Cases for `autotrackMemoize`:__\r\n * - It is likely best used for cases where you need to access specific nested fields\r\n * in data, and avoid recalculating if other fields in the same data objects are immutably updated.\r\n *\r\n * @param func - The function to be memoized.\r\n * @returns A memoized function with a `.clearCache()` method attached.\r\n *\r\n * @example\r\n * <caption>Using `createSelector`</caption>\r\n * ```ts\r\n * import { unstable_autotrackMemoize as autotrackMemoize, createSelector } from 'reselect'\r\n *\r\n * const selectTodoIds = createSelector(\r\n * [(state: RootState) => state.todos],\r\n * (todos) => todos.map(todo => todo.id),\r\n * { memoize: autotrackMemoize }\r\n * )\r\n * ```\r\n *\r\n * @example\r\n * <caption>Using `createSelectorCreator`</caption>\r\n * ```ts\r\n * import { unstable_autotrackMemoize as autotrackMemoize, createSelectorCreator } from 'reselect'\r\n *\r\n * const createSelectorAutotrack = createSelectorCreator({ memoize: autotrackMemoize })\r\n *\r\n * const selectTodoIds = createSelectorAutotrack(\r\n * [(state: RootState) => state.todos],\r\n * (todos) => todos.map(todo => todo.id)\r\n * )\r\n * ```\r\n *\r\n * @template Func - The type of the function that is memoized.\r\n *\r\n * @see {@link https://reselect.js.org/api/unstable_autotrackMemoize autotrackMemoize}\r\n *\r\n * @since 5.0.0\r\n * @public\r\n * @experimental\r\n */\r\nexport function autotrackMemoize<Func extends AnyFunction>(func: Func) {\r\n // we reference arguments instead of spreading them for performance reasons\r\n\r\n const node: Node<Record<string, unknown>> = createNode(\r\n [] as unknown as Record<string, unknown>\r\n )\r\n\r\n let lastArgs: IArguments | null = null\r\n\r\n const shallowEqual = createCacheKeyComparator(referenceEqualityCheck)\r\n\r\n const cache = createCache(() => {\r\n const res = func.apply(null, node.proxy as unknown as any[])\r\n return res\r\n })\r\n\r\n function memoized() {\r\n if (!shallowEqual(lastArgs, arguments)) {\r\n updateNode(node, arguments as unknown as Record<string, unknown>)\r\n lastArgs = arguments\r\n }\r\n return cache.value\r\n }\r\n\r\n memoized.clearCache = () => {\r\n return cache.clear()\r\n }\r\n\r\n return memoized as Func & Simplify<DefaultMemoizeFields>\r\n}\r\n","// Original source:\r\n// - https://github.com/facebook/react/blob/0b974418c9a56f6c560298560265dcf4b65784bc/packages/react/src/ReactCache.js\r\n\r\nimport type {\r\n AnyFunction,\r\n DefaultMemoizeFields,\r\n EqualityFn,\r\n Simplify\r\n} from './types'\r\n\r\nclass StrongRef<T> {\r\n constructor(private value: T) {}\r\n deref() {\r\n return this.value\r\n }\r\n}\r\n\r\nconst Ref =\r\n typeof WeakRef !== 'undefined'\r\n ? WeakRef\r\n : (StrongRef as unknown as typeof WeakRef)\r\n\r\nconst UNTERMINATED = 0\r\nconst TERMINATED = 1\r\n\r\ninterface UnterminatedCacheNode<T> {\r\n /**\r\n * Status, represents whether the cached computation returned a value or threw an error.\r\n */\r\n s: 0\r\n /**\r\n * Value, either the cached result or an error, depending on status.\r\n */\r\n v: void\r\n /**\r\n * Object cache, a `WeakMap` where non-primitive arguments are stored.\r\n */\r\n o: null | WeakMap<Function | Object, CacheNode<T>>\r\n /**\r\n * Primitive cache, a regular Map where primitive arguments are stored.\r\n */\r\n p: null | Map<string | number | null | void | symbol | boolean, CacheNode<T>>\r\n}\r\n\r\ninterface TerminatedCacheNode<T> {\r\n /**\r\n * Status, represents whether the cached computation returned a value or threw an error.\r\n */\r\n s: 1\r\n /**\r\n * Value, either the cached result or an error, depending on status.\r\n */\r\n v: T\r\n /**\r\n * Object cache, a `WeakMap` where non-primitive arguments are stored.\r\n */\r\n o: null | WeakMap<Function | Object, CacheNode<T>>\r\n /**\r\n * Primitive cache, a regular `Map` where primitive arguments are stored.\r\n */\r\n p: null | Map<string | number | null | void | symbol | boolean, CacheNode<T>>\r\n}\r\n\r\ntype CacheNode<T> = TerminatedCacheNode<T> | UnterminatedCacheNode<T>\r\n\r\nfunction createCacheNode<T>(): CacheNode<T> {\r\n return {\r\n s: UNTERMINATED,\r\n v: undefined,\r\n o: null,\r\n p: null\r\n }\r\n}\r\n\r\n/**\r\n * Configuration options for a memoization function utilizing `WeakMap` for\r\n * its caching mechanism.\r\n *\r\n * @template Result - The type of the return value of the memoized function.\r\n *\r\n * @since 5.0.0\r\n * @public\r\n */\r\nexport interface WeakMapMemoizeOptions<Result = any> {\r\n /**\r\n * If provided, used to compare a newly generated output value against previous values in the cache.\r\n * If a match is found, the old value is returned. This addresses the common\r\n * ```ts\r\n * todos.map(todo => todo.id)\r\n * ```\r\n * use case, where an update to another field in the original data causes a recalculation\r\n * due to changed references, but the output is still effectively the same.\r\n *\r\n * @since 5.0.0\r\n */\r\n resultEqualityCheck?: EqualityFn<Result>\r\n}\r\n\r\n/**\r\n * Creates a tree of `WeakMap`-based cache nodes based on the identity of the\r\n * arguments it's been called with (in this case, the extracted values from your input selectors).\r\n * This allows `weakMapMemoize` to have an effectively infinite cache size.\r\n * Cache results will be kept in memory as long as references to the arguments still exist,\r\n * and then cleared out as the arguments are garbage-collected.\r\n *\r\n * __Design Tradeoffs for `weakMapMemoize`:__\r\n * - Pros:\r\n * - It has an effectively infinite cache size, but you have no control over\r\n * how long values are kept in cache as it's based on garbage collection and `WeakMap`s.\r\n * - Cons:\r\n * - There's currently no way to alter the argument comparisons.\r\n * They're based on strict reference equality.\r\n * - It's roughly the same speed as `lruMemoize`, although likely a fraction slower.\r\n *\r\n * __Use Cases for `weakMapMemoize`:__\r\n * - This memoizer is likely best used for cases where you need to call the\r\n * same selector instance with many different arguments, such as a single\r\n * selector instance that is used in a list item component and called with\r\n * item IDs like:\r\n * ```ts\r\n * useSelector(state => selectSomeData(state, props.category))\r\n * ```\r\n * @param func - The function to be memoized.\r\n * @returns A memoized function with a `.clearCache()` method attached.\r\n *\r\n * @example\r\n * <caption>Using `createSelector`</caption>\r\n * ```ts\r\n * import { createSelector, weakMapMemoize } from 'reselect'\r\n *\r\n * interface RootState {\r\n * items: { id: number; category: string; name: string }[]\r\n * }\r\n *\r\n * const selectItemsByCategory = createSelector(\r\n * [\r\n * (state: RootState) => state.items,\r\n * (state: RootState, category: string) => category\r\n * ],\r\n * (items, category) => items.filter(item => item.category === category),\r\n * {\r\n * memoize: weakMapMemoize,\r\n * argsMemoize: weakMapMemoize\r\n * }\r\n * )\r\n * ```\r\n *\r\n * @example\r\n * <caption>Using `createSelectorCreator`</caption>\r\n * ```ts\r\n * import { createSelectorCreator, weakMapMemoize } from 'reselect'\r\n *\r\n * const createSelectorWeakMap = createSelectorCreator({ memoize: weakMapMemoize, argsMemoize: weakMapMemoize })\r\n *\r\n * const selectItemsByCategory = createSelectorWeakMap(\r\n * [\r\n * (state: RootState) => state.items,\r\n * (state: RootState, category: string) => category\r\n * ],\r\n * (items, category) => items.filter(item => item.category === category)\r\n * )\r\n * ```\r\n *\r\n * @template Func - The type of the function that is memoized.\r\n *\r\n * @see {@link https://reselect.js.org/api/weakMapMemoize `weakMapMemoize`}\r\n *\r\n * @since 5.0.0\r\n * @public\r\n * @experimental\r\n */\r\nexport function weakMapMemoize<Func extends AnyFunction>(\r\n func: Func,\r\n options: WeakMapMemoizeOptions<ReturnType<Func>> = {}\r\n) {\r\n let fnNode = createCacheNode()\r\n const { resultEqualityCheck } = options\r\n\r\n let lastResult: WeakRef<object> | undefined\r\n\r\n let resultsCount = 0\r\n\r\n function memoized() {\r\n let cacheNode = fnNode\r\n const { length } = arguments\r\n for (let i = 0, l = length; i < l; i++) {\r\n const arg = arguments[i]\r\n if (\r\n typeof arg === 'function' ||\r\n (typeof arg === 'object' && arg !== null)\r\n ) {\r\n // Objects go into a WeakMap\r\n let objectCache = cacheNode.o\r\n if (objectCache === null) {\r\n cacheNode.o = objectCache = new WeakMap()\r\n }\r\n const objectNode = objectCache.get(arg)\r\n if (objectNode === undefined) {\r\n cacheNode = createCacheNode()\r\n objectCache.set(arg, cacheNode)\r\n } else {\r\n cacheNode = objectNode\r\n }\r\n } else {\r\n // Primitives go into a regular Map\r\n let primitiveCache = cacheNode.p\r\n if (primitiveCache === null) {\r\n cacheNode.p = primitiveCache = new Map()\r\n }\r\n const primitiveNode = primitiveCache.get(arg)\r\n if (primitiveNode === undefined) {\r\n cacheNode = createCacheNode()\r\n primitiveCache.set(arg, cacheNode)\r\n } else {\r\n cacheNode = primitiveNode\r\n }\r\n }\r\n }\r\n\r\n const terminatedNode = cacheNode as unknown as TerminatedCacheNode<any>\r\n\r\n let result\r\n\r\n if (cacheNode.s === TERMINATED) {\r\n result = cacheNode.v\r\n } else {\r\n // Allow errors to propagate\r\n result = func.apply(null, arguments as unknown as any[])\r\n resultsCount++\r\n\r\n if (resultEqualityCheck) {\r\n const lastResultValue = lastResult?.deref?.() ?? lastResult\r\n\r\n if (\r\n lastResultValue != null &&\r\n resultEqualityCheck(lastResultValue as ReturnType<Func>, result)\r\n ) {\r\n result = lastResultValue\r\n\r\n resultsCount !== 0 && resultsCount--\r\n }\r\n\r\n const needsWeakRef =\r\n (typeof result === 'object' && result !== null) ||\r\n typeof result === 'function'\r\n\r\n lastResult = needsWeakRef ? new Ref(result) : result\r\n }\r\n }\r\n\r\n terminatedNode.s = TERMINATED\r\n\r\n terminatedNode.v = result\r\n return result\r\n }\r\n\r\n memoized.clearCache = () => {\r\n fnNode = createCacheNode()\r\n memoized.resetResultsCount()\r\n }\r\n\r\n memoized.resultsCount = () => resultsCount\r\n\r\n memoized.resetResultsCount = () => {\r\n resultsCount = 0\r\n }\r\n\r\n return memoized as Func & Simplify<DefaultMemoizeFields>\r\n}\r\n","import { weakMapMemoize } from './weakMapMemoize'\r\n\r\nimport type {\r\n Combiner,\r\n CreateSelectorOptions,\r\n DropFirstParameter,\r\n ExtractMemoizerFields,\r\n GetParamsFromSelectors,\r\n GetStateFromSelectors,\r\n InterruptRecursion,\r\n OutputSelector,\r\n Selector,\r\n SelectorArray,\r\n SetRequired,\r\n Simplify,\r\n UnknownMemoizer\r\n} from './types'\r\n\r\nimport {\r\n assertIsFunction,\r\n collectInputSelectorResults,\r\n ensureIsArray,\r\n getDependencies,\r\n getDevModeChecksExecutionInfo\r\n} from './utils'\r\n\r\n/**\r\n * An instance of `createSelector`, customized with a given memoize implementation.\r\n *\r\n * @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).\r\n * @template 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.\r\n * @template StateType - The type of state that the selectors created with this selector creator will operate on.\r\n *\r\n * @public\r\n */\r\nexport interface CreateSelectorFunction<\r\n MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,\r\n ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,\r\n StateType = any\r\n> {\r\n /**\r\n * Creates a memoized selector function.\r\n *\r\n * @param createSelectorArgs - An arbitrary number of input selectors as separate inline arguments and a `combiner` function.\r\n * @returns A memoized output selector.\r\n *\r\n * @template InputSelectors - The type of the input selectors as an array.\r\n * @template Result - The return type of the `combiner` as well as the output selector.\r\n * @template 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`.\r\n * @template 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`.\r\n *\r\n * @see {@link https://reselect.js.org/api/createselector `createSelector`}\r\n */\r\n <InputSelectors extends SelectorArray<StateType>, Result>(\r\n ...createSelectorArgs: [\r\n ...inputSelectors: InputSelectors,\r\n combiner: Combiner<InputSelectors, Result>\r\n ]\r\n ): OutputSelector<\r\n InputSelectors,\r\n Result,\r\n MemoizeFunction,\r\n ArgsMemoizeFunction\r\n > &\r\n InterruptRecursion\r\n\r\n /**\r\n * Creates a memoized selector function.\r\n *\r\n * @param createSelectorArgs - An arbitrary number of input selectors as separate inline arguments, a `combiner` function and an `options` object.\r\n * @returns A memoized output selector.\r\n *\r\n * @template InputSelectors - The type of the input selectors as an array.\r\n * @template Result - The return type of the `combiner` as well as the output selector.\r\n * @template 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`.\r\n * @template 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`.\r\n *\r\n * @see {@link https://reselect.js.org/api/createselector `createSelector`}\r\n */\r\n <\r\n InputSelectors extends SelectorArray<StateType>,\r\n Result,\r\n OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction,\r\n OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction\r\n >(\r\n ...createSelectorArgs: [\r\n ...inputSelectors: InputSelectors,\r\n combiner: Combiner<InputSelectors, Result>,\r\n createSelectorOptions: Simplify<\r\n CreateSelectorOptions<\r\n MemoizeFunction,\r\n ArgsMemoizeFunction,\r\n OverrideMemoizeFunction,\r\n OverrideArgsMemoizeFunction\r\n >\r\n >\r\n ]\r\n ): OutputSelector<\r\n InputSelectors,\r\n Result,\r\n OverrideMemoizeFunction,\r\n OverrideArgsMemoizeFunction\r\n > &\r\n InterruptRecursion\r\n\r\n /**\r\n * Creates a memoized selector function.\r\n *\r\n * @param inputSelectors - An array of input selectors.\r\n * @param combiner - A function that Combines the input selectors and returns an output selector. Otherwise known as the result function.\r\n * @param createSelectorOptions - An optional options object that allows for further customization per selector.\r\n * @returns A memoized output selector.\r\n *\r\n * @template InputSelectors - The type of the input selectors array.\r\n * @template Result - The return type of the `combiner` as well as the output selector.\r\n * @template 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`.\r\n * @template 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`.\r\n *\r\n * @see {@link https://reselect.js.org/api/createselector `createSelector`}\r\n */\r\n <\r\n InputSelectors extends SelectorArray<StateType>,\r\n Result,\r\n OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction,\r\n OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction\r\n >(\r\n inputSelectors: [...InputSelectors],\r\n combiner: Combiner<InputSelectors, Result>,\r\n createSelectorOptions?: Simplify<\r\n CreateSelectorOptions<\r\n MemoizeFunction,\r\n ArgsMemoizeFunction,\r\n OverrideMemoizeFunction,\r\n OverrideArgsMemoizeFunction\r\n >\r\n >\r\n ): OutputSelector<\r\n InputSelectors,\r\n Result,\r\n OverrideMemoizeFunction,\r\n OverrideArgsMemoizeFunction\r\n > &\r\n InterruptRecursion\r\n\r\n /**\r\n * Creates a \"pre-typed\" version of {@linkcode createSelector createSelector}\r\n * where the `state` type is predefined.\r\n *\r\n * This allows you to set the `state` type once, eliminating the need to\r\n * specify it with every {@linkcode createSelector createSelector} call.\r\n *\r\n * @returns A pre-typed `createSelector` with the state type already defined.\r\n *\r\n * @example\r\n * ```ts\r\n * import { createSelector } from 'reselect'\r\n *\r\n * export interface RootState {\r\n * todos: { id: number; completed: boolean }[]\r\n * alerts: { id: number; read: boolean }[]\r\n * }\r\n *\r\n * export const createAppSelector = createSelector.withTypes<RootState>()\r\n *\r\n * const selectTodoIds = createAppSelector(\r\n * [\r\n * // Type of `state` is set to `RootState`, no need to manually set the type\r\n * state => state.todos\r\n * ],\r\n * todos => todos.map(({ id }) => id)\r\n * )\r\n * ```\r\n * @template OverrideStateType - The specific type of state used by all selectors created with this selector creator.\r\n *\r\n * @see {@link https://reselect.js.org/api/createselector#defining-a-pre-typed-createselector `createSelector.withTypes`}\r\n *\r\n * @since 5.1.0\r\n */\r\n withTypes: <OverrideStateType extends StateType>() => CreateSelectorFunction<\r\n MemoizeFunction,\r\n ArgsMemoizeFunction,\r\n OverrideStateType\r\n >\r\n}\r\n\r\n/**\r\n * Creates a selector creator function with the specified memoization function\r\n * and options for customizing memoization behavior.\r\n *\r\n * @param options - An options object containing the `memoize` function responsible for memoizing the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). It also provides additional options for customizing memoization. While the `memoize` property is mandatory, the rest are optional.\r\n * @returns A customized `createSelector` function.\r\n *\r\n * @example\r\n * ```ts\r\n * const customCreateSelector = createSelectorCreator({\r\n * memoize: custo