Socket
Socket
Sign inDemoInstall

reselect

Package Overview
Dependencies
Maintainers
6
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

reselect - npm Package Compare versions

Comparing version 5.0.0-beta.0 to 5.0.0-beta.1

821

dist/reselect.d.ts

@@ -0,35 +1,98 @@

/**
* @public
*/
declare const defaultEqualityCheck: EqualityFn;
/**
* @public
*/
interface DefaultMemoizeOptions {
/**
* Used to compare the individual arguments of the provided calculation function.
*
* @default defaultEqualityCheck
*/
equalityCheck?: EqualityFn;
/**
* 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
* ```ts
* todos.map(todo => todo.id)
* ```
* 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.
*/
resultEqualityCheck?: EqualityFn;
/**
* The cache size for the selector. If greater than 1, the selector will use an LRU cache internally.
*
* @default 1
*/
maxSize?: number;
}
declare function defaultMemoize<F extends AnyFunction>(func: F, equalityCheckOrOptions?: EqualityFn | DefaultMemoizeOptions): F & {
/**
* The standard memoize function used by `createSelector`.
* @param func - The function to be memoized.
* @param equalityCheckOrOptions - Either an equality check function or an options object.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @template Func - The type of the function that is memoized.
*
* @see {@link https://github.com/reduxjs/reselect#defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck defaultMemoize}
*
* @public
*/
declare function defaultMemoize<Func extends AnyFunction>(func: Func, equalityCheckOrOptions?: EqualityFn | DefaultMemoizeOptions): Func & {
clearCache: () => void;
};
/**
* @internal
*/
type LongestTuple<T extends readonly unknown[][]> = T extends [
infer U extends unknown[]
] ? U : T extends [infer U, ...infer R extends unknown[][]] ? MostProperties<U, LongestTuple<R>> : never;
/**
* @internal
*/
type MostProperties<T, U> = keyof U extends keyof T ? T : U;
/**
* @internal
*/
type ElementAt<T extends unknown[], N extends keyof any> = N extends keyof T ? T[N] : unknown;
/**
* @internal
*/
type ElementsAt<T extends readonly unknown[][], N extends keyof any> = {
[K in keyof T]: ElementAt<T[K], N>;
};
/**
* @internal
*/
type Intersect<T extends readonly unknown[]> = T extends [] ? unknown : T extends [infer H, ...infer T] ? H & Intersect<T> : T[number];
/**
* @internal
*/
type MergeTuples<T extends readonly unknown[][], L extends unknown[] = LongestTuple<T>> = {
[K in keyof L]: Intersect<ElementsAt<T, K>>;
};
/**
* @internal
*/
type ExtractParameters<T extends readonly AnyFunction[]> = {
[K in keyof T]: Parameters<T[K]>;
};
/**
* @internal
*/
type MergeParameters<T extends readonly AnyFunction[]> = '0' extends keyof T ? MergeTuples<ExtractParameters<T>> : Parameters<T[number]>;
/**
* A standard selector function, which takes three generic type arguments:
* @template State - The first value, often a Redux root state object
* @template Result - The final result returned by the selector
* @template Params - All additional arguments passed into the selector
* A standard selector function.
* @template State - The first value, often a Redux root state object.
* @template Result - The final result returned by the selector.
* @template Params - All additional arguments passed into the selector.
*
* @public
*/
type Selector<State = any, Result = unknown, Params extends readonly any[] = any[]> =
type Selector<State = any, Result = unknown, Params extends readonly any[] = any[]> = Distribute<
/**

@@ -42,18 +105,104 @@ * A function that takes a state and returns data that is based on that state.

*/
(state: State, ...params: FallbackIfNever<Params, []>) => Result;
(state: State, ...params: FallbackIfNever<Params, []>) => Result>;
/**
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
* An array of input selectors.
*
* @template InputSelectors - An array of input selectors.
* @template Result - Result returned by `resultFunc`.
* @public
*/
type Combiner<InputSelectors extends SelectorArray, Result> =
type SelectorArray = readonly Selector[];
/**
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
* Extracts an array of all return types from all input selectors.
*
* @param resultFuncArgs - Return values of input selectors.
* @returns The return value of {@linkcode OutputSelectorFields.resultFunc resultFunc}.
* @public
*/
(...resultFuncArgs: SelectorResultArray<InputSelectors>) => Result;
type SelectorResultArray<Selectors extends SelectorArray> = ExtractReturnType<Selectors>;
/**
* The options object used inside `createSelector` and `createSelectorCreator`.
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
* @template OverrideMemoizeFunction - The type of the optional `memoize` function that could be passed into the options object inside `createSelector` to override the original `memoize` function that was initially passed into `createSelectorCreator`.
* @template OverrideArgsMemoizeFunction - The type of the optional `argsMemoize` function that could be passed into the options object inside `createSelector` to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`. If none was initially provided, `defaultMemoize` will be used.
*
* @public
*/
interface CreateSelectorOptions<MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, OverrideMemoizeFunction extends UnknownMemoizer = never, OverrideArgsMemoizeFunction extends UnknownMemoizer = never> {
/**
* Overrides the global input stability check for the selector.
* - `once` - Run only the first time the selector is called.
* - `always` - Run every time the selector is called.
* - `never` - Never run the input stability check.
*
* @default 'once'
*
* @see {@link https://github.com/reduxjs/reselect#development-only-checks development-only-checks}
* @see {@link https://github.com/reduxjs/reselect#inputstabilitycheck inputStabilityCheck}
* @see {@link https://github.com/reduxjs/reselect#per-selector-configuration per-selector-configuration}
*
* @since 5.0.0
*/
inputStabilityCheck?: StabilityCheckFrequency;
/**
* The memoize function that is used to memoize the {@linkcode OutputSelectorFields.resultFunc resultFunc}
* inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `memoize` function initially passed into `createSelectorCreator`.
*
* @example
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* const selectTodoById = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState, id: number) => id
* ],
* (todos) => todos[id],
* { memoize: weakMapMemoize }
* )
* ```
*
* @since 5.0.0
*/
memoize: FallbackIfNever<OverrideMemoizeFunction, MemoizeFunction>;
/**
* The optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `argsMemoize` function initially passed into `createSelectorCreator`. If none was initially provided, `defaultMemoize` will be used.
*
* @example
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* const selectTodoById = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState, id: number) => id
* ],
* (todos) => todos[id],
* { argsMemoize: weakMapMemoize }
* )
* ```
*
* @default defaultMemoize
*
* @since 5.0.0
*/
argsMemoize?: FallbackIfNever<OverrideArgsMemoizeFunction, ArgsMemoizeFunction>;
/**
* Optional configuration options for the {@linkcode CreateSelectorOptions.memoize memoize} function.
* These options are passed to the {@linkcode CreateSelectorOptions.memoize memoize} function as the second argument.
*
* @since 5.0.0
*/
memoizeOptions?: OverrideMemoizeOptions<MemoizeFunction, OverrideMemoizeFunction>;
/**
* Optional configuration options for the {@linkcode CreateSelectorOptions.argsMemoize argsMemoize} function.
* These options are passed to the {@linkcode CreateSelectorOptions.argsMemoize argsMemoize} function as the second argument.
*
* @since 5.0.0
*/
argsMemoizeOptions?: OverrideMemoizeOptions<ArgsMemoizeFunction, OverrideArgsMemoizeFunction>;
}
/**
* The additional fields attached to the output selector generated by `createSelector`.

@@ -73,7 +222,9 @@ *

* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @public
*/
interface OutputSelectorFields<InputSelectors extends SelectorArray = SelectorArray, Result = unknown, MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize> extends Required<Pick<CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction>, 'argsMemoize' | 'memoize'>> {
/** The final function passed to `createSelector`. Otherwise known as the `combiner`. */
type OutputSelectorFields<InputSelectors extends SelectorArray = SelectorArray, Result = unknown, MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize> = {
/** The final function passed to `createSelector`. Otherwise known as the `combiner`.*/
resultFunc: Combiner<InputSelectors, Result>;
/** The memoized version of {@linkcode resultFunc resultFunc}. */
/** The memoized version of {@linkcode OutputSelectorFields.resultFunc resultFunc}. */
memoizedResultFunc: Combiner<InputSelectors, Result> & ExtractMemoizerFields<MemoizeFunction>;

@@ -88,3 +239,3 @@ /** Returns the last result calculated by the output selector. */

resetRecomputations: () => 0;
}
} & Simplify<Required<Pick<CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction>, 'argsMemoize' | 'memoize'>>>;
/**

@@ -97,29 +248,27 @@ * Represents the actual selectors generated by `createSelector`.

* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @public
*/
type OutputSelector<InputSelectors extends SelectorArray = SelectorArray, Result = unknown, MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize> = PrepareOutputSelector<InputSelectors, Result, MemoizeFunction, ArgsMemoizeFunction> & ExtractMemoizerFields<ArgsMemoizeFunction>;
type OutputSelector<InputSelectors extends SelectorArray = SelectorArray, Result = unknown, MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize> = Selector<GetStateFromSelectors<InputSelectors>, Result, GetParamsFromSelectors<InputSelectors>> & ExtractMemoizerFields<ArgsMemoizeFunction> & OutputSelectorFields<InputSelectors, Result, MemoizeFunction, ArgsMemoizeFunction>;
/**
* A helper type designed to optimize TypeScript performance by composing parts of {@linkcode OutputSelector OutputSelector} in a more statically structured manner.
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
*
* This is achieved by utilizing the `extends` keyword with `interfaces`, as opposed to creating intersections with type aliases.
* This approach offers some performance benefits:
* - `Interfaces` create a flat object type, while intersections with type aliases recursively merge properties.
* - Type relationships between `interfaces` are also cached, as opposed to intersection types as a whole.
* - When checking against an intersection type, every constituent is verified before checking against the "effective" flattened type.
* @template InputSelectors - An array of input selectors.
* @template Result - Result returned by `resultFunc`.
*
* This optimization focuses on resolving much of the type composition for
* {@linkcode OutputSelector OutputSelector} using `extends` with `interfaces`,
* rather than relying on intersections for the entire {@linkcode OutputSelector OutputSelector}.
* @public
*/
type Combiner<InputSelectors extends SelectorArray, Result> = Distribute<
/**
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
*
* @template InputSelectors - The type of the input selectors.
* @template Result - The type of the result returned by the `resultFunc`.
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @see {@link https://github.com/microsoft/TypeScript/wiki/Performance#preferring-interfaces-over-intersections Reference}
* @param resultFuncArgs - Return values of input selectors.
* @returns The return value of {@linkcode OutputSelectorFields.resultFunc resultFunc}.
*/
interface PrepareOutputSelector<InputSelectors extends SelectorArray = SelectorArray, Result = unknown, MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize> extends OutputSelectorFields<InputSelectors, Result, MemoizeFunction, ArgsMemoizeFunction>, Selector<GetStateFromSelectors<InputSelectors>, Result, GetParamsFromSelectors<InputSelectors>> {
}
(...resultFuncArgs: SelectorResultArray<InputSelectors>) => Result>;
/**
* A selector that is assumed to have one additional argument, such as
* the props from a React component
* the props from a React component.
*
* @public
*/

@@ -130,70 +279,54 @@ type ParametricSelector<State, Props, Result> = Selector<State, Result, [

]>;
/** A generated selector that is assumed to have one additional argument */
/**
* A generated selector that is assumed to have one additional argument.
*
* @public
*/
type OutputParametricSelector<State, Props, Result> = ParametricSelector<State, Props, Result> & OutputSelectorFields<SelectorArray, Result>;
/** An array of input selectors */
type SelectorArray = ReadonlyArray<Selector>;
/** A standard function returning true if two values are considered equal */
/**
* A standard function returning true if two values are considered equal.
*
* @public
*/
type EqualityFn = (a: any, b: any) => boolean;
/**
* The frequency of input stability checks.
*
* @since 5.0.0
* @public
*/
type StabilityCheckFrequency = 'always' | 'once' | 'never';
/**
* The options object used inside `createSelector` and `createSelectorCreator`.
* Determines the combined single "State" type (first arg) from all input selectors.
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
* @template OverrideMemoizeFunction - The type of the optional `memoize` function that could be passed into the options object inside `createSelector` to override the original `memoize` function that was initially passed into `createSelectorCreator`.
* @template OverrideArgsMemoizeFunction - The type of the optional `argsMemoize` function that could be passed into the options object inside `createSelector` to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`. If none was initially provided, `defaultMemoize` will be used.
* @public
*/
interface CreateSelectorOptions<MemoizeFunction extends UnknownMemoizer, ArgsMemoizeFunction extends UnknownMemoizer, OverrideMemoizeFunction extends UnknownMemoizer = never, OverrideArgsMemoizeFunction extends UnknownMemoizer = never> {
/**
* Overrides the global input stability check for the selector.
* - `once` - Run only the first time the selector is called.
* - `always` - Run every time the selector is called.
* - `never` - Never run the input stability check.
*
* @default 'once'
*
* @see {@link https://github.com/reduxjs/reselect#development-only-checks development-only-checks}
* @see {@link https://github.com/reduxjs/reselect#inputstabilitycheck inputStabilityCheck}
* @see {@link https://github.com/reduxjs/reselect#per-selector-configuration per-selector-configuration}
*/
inputStabilityCheck?: StabilityCheckFrequency;
/**
* The memoize function that is used to memoize the {@linkcode OutputSelectorFields.resultFunc resultFunc}
* inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `memoize` function initially passed into `createSelectorCreator`.
*/
memoize: FallbackIfNever<OverrideMemoizeFunction, MemoizeFunction>;
/**
* The optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `argsMemoize` function initially passed into `createSelectorCreator`. If none was initially provided, `defaultMemoize` will be used.
*
* @default defaultMemoize
*/
argsMemoize?: FallbackIfNever<OverrideArgsMemoizeFunction, ArgsMemoizeFunction>;
/**
* Optional configuration options for the {@linkcode memoize memoize} function.
* These options are passed to the {@linkcode memoize memoize} function as the second argument.
*/
memoizeOptions?: OverrideMemoizeOptions<MemoizeFunction, OverrideMemoizeFunction>;
/**
* Optional configuration options for the {@linkcode argsMemoize argsMemoize} function.
* These options are passed to the {@linkcode argsMemoize argsMemoize} function as the second argument.
*/
argsMemoizeOptions?: OverrideMemoizeOptions<ArgsMemoizeFunction, OverrideArgsMemoizeFunction>;
}
/** Extracts an array of all return types from all input selectors */
type SelectorResultArray<Selectors extends SelectorArray> = ExtractReturnType<Selectors>;
/** Determines the combined single "State" type (first arg) from all input selectors */
type GetStateFromSelectors<Selectors extends SelectorArray> = MergeParameters<Selectors>[0];
/** Determines the combined "Params" type (all remaining args) from all input selectors */
type GetParamsFromSelectors<Selectors extends SelectorArray, RemainingItems extends readonly unknown[] = Tail<MergeParameters<Selectors>>> = RemainingItems;
/** Any function with any arguments */
/**
* Determines the combined "Params" type (all remaining args) from all input selectors.
*
* @public
*/
type GetParamsFromSelectors<Selectors extends SelectorArray> = ArrayTail<MergeParameters<Selectors>>;
/**
* Any function with any arguments.
*
* @internal
*/
type AnyFunction = (...args: any[]) => any;
/** Any function with unknown arguments */
/**
* Any function with unknown arguments.
*
* @internal
*/
type UnknownFunction = (...args: unknown[]) => unknown;
/** Any Memoizer function. A memoizer is a function that accepts another function and returns it. */
type UnknownMemoizer<Func extends UnknownFunction = UnknownFunction> = (func: Func, ...options: any[]) => Func;
/**
* Any Memoizer function. A memoizer is a function that accepts another function and returns it.
*
* @template FunctionType - The type of the function that is memoized.
*
* @internal
*/
type UnknownMemoizer<FunctionType extends UnknownFunction = UnknownFunction> = (func: FunctionType, ...options: any[]) => FunctionType;
/**
* When a generic type parameter is using its default value of `never`, fallback to a different type.

@@ -203,2 +336,4 @@ *

* @template FallbackTo - Type to fallback to if `T` resolves to `never`.
*
* @internal
*/

@@ -213,28 +348,99 @@ type FallbackIfNever<T, FallbackTo> = IfNever<T, FallbackTo, T>;

* @template OverrideMemoizeFunction - The type of the optional `memoize` or `argsMemoize` function passed directly into `createSelector` which then overrides the original `memoize` or `argsMemoize` function passed into `createSelectorCreator`.
*
* @internal
*/
type OverrideMemoizeOptions<MemoizeFunction extends UnknownMemoizer, OverrideMemoizeFunction extends UnknownMemoizer = never> = IfNever<OverrideMemoizeFunction, MemoizeOptionsFromParameters<MemoizeFunction>, MemoizeOptionsFromParameters<OverrideMemoizeFunction>>;
/**
* Extract the memoize options from the parameters of a memoize function.
* Extracts the non-function part of a type.
*
* @template T - The input type to be refined by excluding function types and index signatures.
*
* @internal
*/
type NonFunctionType<T> = OmitIndexSignature<Exclude<T, AnyFunction>>;
/**
* Extracts the function part of a type.
*
* @template T - The input type to be refined by extracting function types.
*
* @internal
*/
type FunctionType<T> = Extract<T, AnyFunction>;
/**
* Extracts the options type for a memoization function based on its parameters.
* The first parameter of the function is expected to be the function to be memoized,
* followed by options for the memoization process.
*
* @template MemoizeFunction - The type of the memoize function to be checked.
*
* @internal
*/
type MemoizeOptionsFromParameters<MemoizeFunction extends UnknownMemoizer> = DropFirstParameter<MemoizeFunction>[0] | DropFirstParameter<MemoizeFunction>;
type MemoizeOptionsFromParameters<MemoizeFunction extends UnknownMemoizer> = (Simplify<NonFunctionType<DropFirstParameter<MemoizeFunction>[0]>> | FunctionType<DropFirstParameter<MemoizeFunction>[0]>) | (Simplify<NonFunctionType<DropFirstParameter<MemoizeFunction>[number]>> | FunctionType<DropFirstParameter<MemoizeFunction>[number]>)[];
/**
* Extracts the additional fields that a memoize function attaches to the function it memoizes (e.g., `clearCache`).
* Extracts the additional fields that a memoize function attaches to
* the function it memoizes (e.g., `clearCache`).
*
* @template MemoizeFunction - The type of the memoize function to be checked.
*
* @internal
*/
type ExtractMemoizerFields<MemoizeFunction extends UnknownMemoizer> = OmitIndexSignature<ReturnType<MemoizeFunction>>;
/** Extract the return type from all functions as a tuple */
type ExtractReturnType<T extends readonly AnyFunction[]> = {
[index in keyof T]: T[index] extends T[number] ? ReturnType<T[index]> : never;
type ExtractMemoizerFields<MemoizeFunction extends UnknownMemoizer> = Simplify<OmitIndexSignature<ReturnType<MemoizeFunction>>>;
/**
* Extracts the return type from all functions as a tuple.
*
* @internal
*/
type ExtractReturnType<FunctionsArray extends readonly AnyFunction[]> = {
[Index in keyof FunctionsArray]: FunctionsArray[Index] extends FunctionsArray[number] ? ReturnType<FunctionsArray[Index]> : never;
};
/** First item in an array */
type Head<T> = T extends [any, ...any[]] ? T[0] : never;
/** All other items in an array */
type Tail<A> = A extends [any, ...infer Rest] ? Rest : never;
/**
* Utility type to infer the type of "all params of a function except the first",
* so we can determine what arguments a memoize function accepts.
*
* @internal
*/
type DropFirstParameter<Func extends AnyFunction> = Func extends (firstArg: any, ...restArgs: infer Rest) => any ? Rest : never;
/**
* Distributes over a type. It is used mostly to expand a function type
* in hover previews while preserving their original JSDoc information.
*
* If preserving JSDoc information is not a concern, you can use {@linkcode ExpandFunction ExpandFunction}.
*
* @template T The type to be distributed.
*
* @internal
*/
type Distribute<T> = T extends T ? T : never;
/**
* Extracts the type of an array or tuple minus the first element.
*
* @internal
*/
type ArrayTail<TArray> = TArray extends readonly [
unknown,
...infer TTail
] ? TTail : [];
/**
* An alias for type `{}`. Represents any value that is not `null` or `undefined`.
* It is mostly used for semantic purposes to help distinguish between an
* empty object type and `{}` as they are not the same.
*
* @internal
*/
type AnyNonNullishValue = NonNullable<unknown>;
/**
* Same as {@linkcode AnyNonNullishValue AnyNonNullishValue} but aliased
* for semantic purposes. It is intended to be used in scenarios where
* a recursive type definition needs to be interrupted to ensure type safety
* and to avoid excessively deep recursion that could lead to performance issues.
*
* @internal
*/
type InterruptRecursion = AnyNonNullishValue;
/**
* An if-else-like type that resolves depending on whether the given type is `never`.
* This is mainly used to conditionally resolve the type of a `memoizeOptions` object based on whether `memoize` is provided or not.
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/if-never.d.ts Source}
*
* @internal
*/

@@ -245,3 +451,9 @@ type IfNever<T, TypeIfNever, TypeIfNotNever> = [T] extends [never] ? TypeIfNever : TypeIfNotNever;

* This is mainly used to remove explicit `any`s from the return type of some memoizers (e.g, `microMemoize`).
*
* __Disclaimer:__ When used on an intersection of a function and an object,
* the function is erased.
*
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/omit-index-signature.d.ts Source}
*
* @internal
*/

@@ -253,4 +465,6 @@ type OmitIndexSignature<ObjectType> = {

* The infamous "convert a union type to an intersection type" hack
* Source: https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts
* Reference: https://github.com/microsoft/TypeScript/issues/29594
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts Source}
* @see {@link https://github.com/microsoft/TypeScript/issues/29594 Reference}
*
* @internal
*/

@@ -260,23 +474,103 @@ type UnionToIntersection<Union> = (Union extends unknown ? (distributedUnion: Union) => void : never) extends (mergedIntersection: infer Intersection) => void ? Intersection : never;

* Code to convert a union of values into a tuple.
* Source: https://stackoverflow.com/a/55128956/62937
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
type Push<T extends any[], V> = [...T, V];
/**
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never;
/**
* TS4.1+
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>;
/**
* Converts "the values of an object" into a tuple, like a type-level `Object.values()`
* Source: https://stackoverflow.com/a/68695508/62937
* @see {@link https://stackoverflow.com/a/68695508/62937 Source}
*
* @internal
*/
type ObjValueTuple<T, KS extends any[] = TuplifyUnion<keyof T>, R extends any[] = []> = KS extends [infer K, ...infer KT] ? ObjValueTuple<T, KT, [...R, T[K & keyof T]]> : R;
/** Utility type to infer the type of "all params of a function except the first", so we can determine what arguments a memoize function accepts */
type DropFirstParameter<Func extends AnyFunction> = Func extends (firstArg: any, ...restArgs: infer Rest) => any ? Rest : never;
type ObjectValuesToTuple<T, KS extends any[] = TuplifyUnion<keyof T>, R extends any[] = []> = KS extends [infer K, ...infer KT] ? ObjectValuesToTuple<T, KT, [...R, T[K & keyof T]]> : R;
/**
* Useful to flatten the type output to improve type hints shown in editors.
* And also to transform an interface into a type to aide with assignability.
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts Source}
*
* @internal
*/
type Simplify<T> = {
[KeyType in keyof T]: T[KeyType];
} & AnyNonNullishValue;
declare function autotrackMemoize<F extends AnyFunction>(func: F): F & {
/**
* Uses an "auto-tracking" approach inspired by the work of the Ember Glimmer team.
* It uses a Proxy to wrap arguments and track accesses to nested fields
* in your selector on first read. Later, when the selector is called with
* new arguments, it identifies which accessed fields have changed and
* only recalculates the result if one or more of those accessed fields have changed.
* This allows it to be more precise than the shallow equality checks in `defaultMemoize`.
*
* __Design Tradeoffs for `autotrackMemoize`:__
* - Pros:
* - It is likely to avoid excess calculations and recalculate fewer times than `defaultMemoize` will,
* which may also result in fewer component re-renders.
* - Cons:
* - It only has a cache size of 1.
* - It is slower than `defaultMemoize`, 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)
* - It can have some unexpected behavior. Because it tracks nested field accesses,
* cases where you don't access a field will not recalculate properly.
* For example, a badly-written selector like:
* ```ts
* createSelector([state => state.todos], todos => todos)
* ```
* that just immediately returns the extracted value will never update, because it doesn't see any field accesses to check.
*
* __Use Cases for `autotrackMemoize`:__
* - It is likely best used for cases where you need to access specific nested fields
* in data, and avoid recalculating if other fields in the same data objects are immutably updated.
*
* @param func - The function to be memoized.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @example
* <caption>Using `createSelector`</caption>
* ```ts
* import { unstable_autotrackMemoize as autotrackMemoize, createSelector } from 'reselect'
*
* const selectTodoIds = createSelector(
* [(state: RootState) => state.todos],
* (todos) => todos.map(todo => todo.id),
* { memoize: autotrackMemoize }
* )
* ```
*
* @example
* <caption>Using `createSelectorCreator`</caption>
* ```ts
* import { unstable_autotrackMemoize as autotrackMemoize, createSelectorCreator } from 'reselect'
*
* const createSelectorAutotrack = createSelectorCreator(autotrackMemoize)
*
* const selectTodoIds = createSelectorAutotrack(
* [(state: RootState) => state.todos],
* (todos) => todos.map(todo => todo.id)
* )
* ```
*
* @template Func - The type of the function that is memoized.
*
* @since 5.0.0
* @public
* @experimental
*/
declare function autotrackMemoize<Func extends AnyFunction>(func: Func): Func & {
clearCache: () => void;
};
declare function weakMapMemoize<F extends AnyFunction>(func: F): F & {
clearCache: () => void;
};
/**

@@ -287,4 +581,6 @@ * An instance of `createSelector`, customized with a given memoize implementation.

* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @public
*/
interface CreateSelectorFunction<MemoizeFunction extends UnknownMemoizer, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize> {
interface CreateSelectorFunction<MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize> {
/**

@@ -294,3 +590,3 @@ * Creates a memoized selector function.

* @param createSelectorArgs - An arbitrary number of input selectors as separate inline arguments and a `combiner` function.
* @returns An output selector.
* @returns A memoized output selector.
*

@@ -301,2 +597,4 @@ * @template InputSelectors - The type of the input selectors as an array.

* @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`.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions createSelector}
*/

@@ -306,3 +604,3 @@ <InputSelectors extends SelectorArray, Result>(...createSelectorArgs: [

combiner: Combiner<InputSelectors, Result>
]): OutputSelector<InputSelectors, Result, MemoizeFunction, ArgsMemoizeFunction>;
]): OutputSelector<InputSelectors, Result, MemoizeFunction, ArgsMemoizeFunction> & InterruptRecursion;
/**

@@ -312,3 +610,3 @@ * Creates a memoized selector function.

* @param createSelectorArgs - An arbitrary number of input selectors as separate inline arguments, a `combiner` function and an `options` object.
* @returns An output selector.
* @returns A memoized output selector.
*

@@ -319,2 +617,4 @@ * @template InputSelectors - The type of the input selectors as an array.

* @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`.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions createSelector}
*/

@@ -325,3 +625,3 @@ <InputSelectors extends SelectorArray, Result, OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction, OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction>(...createSelectorArgs: [

createSelectorOptions: Partial<CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction, OverrideMemoizeFunction, OverrideArgsMemoizeFunction>>
]): OutputSelector<InputSelectors, Result, OverrideMemoizeFunction, OverrideArgsMemoizeFunction>;
]): OutputSelector<InputSelectors, Result, OverrideMemoizeFunction, OverrideArgsMemoizeFunction> & InterruptRecursion;
/**

@@ -333,3 +633,3 @@ * Creates a memoized selector function.

* @param createSelectorOptions - An optional options object that allows for further customization per selector.
* @returns An output selector.
* @returns A memoized output selector.
*

@@ -340,4 +640,6 @@ * @template InputSelectors - The type of the input selectors array.

* @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`.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions createSelector}
*/
<InputSelectors extends SelectorArray, Result, OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction, OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction>(inputSelectors: [...InputSelectors], combiner: Combiner<InputSelectors, Result>, createSelectorOptions?: Partial<CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction, OverrideMemoizeFunction, OverrideArgsMemoizeFunction>>): OutputSelector<InputSelectors, Result, OverrideMemoizeFunction, OverrideArgsMemoizeFunction>;
<InputSelectors extends SelectorArray, Result, OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction, OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction>(inputSelectors: [...InputSelectors], combiner: Combiner<InputSelectors, Result>, createSelectorOptions?: Partial<CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction, OverrideMemoizeFunction, OverrideArgsMemoizeFunction>>): OutputSelector<InputSelectors, Result, OverrideMemoizeFunction, OverrideArgsMemoizeFunction> & InterruptRecursion;
}

@@ -362,2 +664,4 @@ /**

* import { setInputStabilityCheckEnabled } from 'reselect'
import { assert } from './autotrackMemoize/utils';
import { OutputSelectorFields, Mapped } from './types';
*

@@ -375,2 +679,5 @@ * // Run only the first time the selector is called. (default)

* @see {@link https://github.com/reduxjs/reselect#global-configuration global-configuration}
*
* @since 5.0.0
* @public
*/

@@ -405,4 +712,9 @@ declare function setInputStabilityCheckEnabled(inputStabilityCheckFrequency: StabilityCheckFrequency): void;

* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorcreatormemoize-memoizeoptions createSelectorCreator}
*
* @since 5.0.0
* @public
*/
declare function createSelectorCreator<MemoizeFunction extends UnknownMemoizer, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize>(options: CreateSelectorOptions<MemoizeFunction, typeof defaultMemoize, never, ArgsMemoizeFunction>): CreateSelectorFunction<MemoizeFunction, ArgsMemoizeFunction>;
declare function createSelectorCreator<MemoizeFunction extends UnknownMemoizer, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize>(options: CreateSelectorOptions<typeof defaultMemoize, typeof defaultMemoize, MemoizeFunction, ArgsMemoizeFunction>): CreateSelectorFunction<MemoizeFunction, ArgsMemoizeFunction>;
/**

@@ -430,19 +742,258 @@ * Creates a selector creator function with the specified memoization function and options for customizing memoization behavior.

* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* @see {@link https://github.com/reduxjs/reselect#createselectorcreatormemoize-memoizeoptions createSelectorCreator}
*
* @public
*/
declare function createSelectorCreator<MemoizeFunction extends UnknownMemoizer>(memoize: MemoizeFunction, ...memoizeOptionsFromArgs: DropFirstParameter<MemoizeFunction>): CreateSelectorFunction<MemoizeFunction>;
/**
* Accepts one or more "input selectors" (either as separate arguments or a single array),
* a single "result function" / "combiner", and an optional options object, and
* generates a memoized selector function.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions createSelector}
*
* @public
*/
declare const createSelector: CreateSelectorFunction<typeof defaultMemoize, typeof defaultMemoize>;
/**
*
* @WIP
*/
type SelectorsMap<T extends SelectorsObject> = {
[Key in keyof T]: ReturnType<T[Key]>;
};
/**
* Allows you to create a pre-typed version of {@linkcode createStructuredSelector createStructuredSelector}
* For your root state.
*
* @since 5.0.0
* @public
* @WIP
*/
interface TypedStructuredSelectorCreator<RootState = any> {
<InputSelectorsObject extends {
[Key in keyof RootState]: Selector<RootState, RootState[Key], []>;
} = {
[Key in keyof RootState]: Selector<RootState, RootState[Key], []>;
}, MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize>(selectors: InputSelectorsObject, selectorCreator?: CreateSelectorFunction<MemoizeFunction, ArgsMemoizeFunction>): OutputSelector<ObjectValuesToTuple<InputSelectorsObject>, SelectorsMap<InputSelectorsObject>, MemoizeFunction, ArgsMemoizeFunction>;
}
interface SelectorsObject {
[key: string]: AnyFunction;
[key: string]: Selector;
}
/**
* It provides a way to create structured selectors.
* The structured selector can take multiple input selectors
* and map their output to an object with specific keys.
*
* @see {@link https://github.com/reduxjs/reselect#createstructuredselectorinputselectors-selectorcreator--createselector createStructuredSelector}
*
* @public
*/
interface StructuredSelectorCreator {
<SelectorMap extends SelectorsObject, SelectorParams = MergeParameters<ObjValueTuple<SelectorMap>>>(selectorMap: SelectorMap, selectorCreator?: CreateSelectorFunction<any, any>): (state: Head<SelectorParams>, ...params: Tail<SelectorParams>) => {
[Key in keyof SelectorMap]: ReturnType<SelectorMap[Key]>;
};
<State, Result = State>(selectors: {
[K in keyof Result]: Selector<State, Result[K], never>;
}, selectorCreator?: CreateSelectorFunction<any, any>): Selector<State, Result, never>;
/**
* A convenience function for a common pattern that arises when using Reselect.
* The selector passed to a `connect` decorator often just takes the
* values of its input selectors and maps them to keys in an object.
*
* @param selectorMap - A key value pair consisting of input selectors.
* @param selectorCreator - A custom selector creator function. It defaults to `createSelector`.
* @returns A memoized structured selector.
*
* @example
* <caption>Modern Use Case</caption>
* ```ts
* import { createSelector, createStructuredSelector } from 'reselect'
*
* interface State {
* todos: {
* id: number
* title: string
* description: string
* completed: boolean
* }[]
* alerts: {
* id: number
* message: string
* type: 'reminder' | 'notification'
* read: boolean
* }[]
* }
*
* const state: State = {
* todos: [
* {
* id: 0,
* title: 'Buy groceries',
* description: 'Milk, bread, eggs, and fruits',
* completed: false
* },
* {
* id: 1,
* title: 'Schedule dentist appointment',
* description: 'Check available slots for next week',
* completed: true
* }
* ],
* alerts: [
* {
* id: 0,
* message: 'You have an upcoming meeting at 3 PM.',
* type: 'reminder',
* read: false
* },
* {
* id: 1,
* message: 'New software update available.',
* type: 'notification',
* read: true
* }
* ]
* }
*
* // This:
* const structuredSelector = createStructuredSelector(
* {
* allTodos: (state: State) => state.todos,
* allAlerts: (state: State) => state.alerts,
* selectedTodo: (state: State, id: number) => state.todos[id]
* },
* createSelector
* )
*
* // Is essentially the same as this:
* const selector = createSelector(
* [
* (state: State) => state.todos,
* (state: State) => state.alerts,
* (state: State, id: number) => state.todos[id]
* ],
* (allTodos, allAlerts, selectedTodo) => {
* return {
* allTodos,
* allAlerts,
* selectedTodo
* }
* }
* )
* ```
*
* @example
* <caption>Simple Use Case</caption>
* ```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) => ({
* a,
* b
* }))
*
* const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
* ```
*
* @template InputSelectorsObject - The shape of the input selectors object.
* @template MemoizeFunction - The type of the memoize function that is used to create the structured selector. It defaults to `defaultMemoize`.
* @template ArgsMemoizeFunction - The type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `defaultMemoize`.
*
* @see {@link https://github.com/reduxjs/reselect#createstructuredselectorinputselectors-selectorcreator--createselector createStructuredSelector}
*/
<InputSelectorsObject extends SelectorsObject, MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize, ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize>(selectorMap: InputSelectorsObject, selectorCreator?: CreateSelectorFunction<MemoizeFunction, ArgsMemoizeFunction>): OutputSelector<ObjectValuesToTuple<InputSelectorsObject>, SelectorsMap<InputSelectorsObject>, MemoizeFunction, ArgsMemoizeFunction>;
}
/**
* A convenience function for a common pattern that arises when using Reselect.
* The selector passed to a `connect` decorator often just takes the values of its input selectors
* and maps them to keys in an object.
*
* @example
* <caption>Simple Use Case</caption>
* ```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) => ({
* a,
* b
* }))
* ```
*
* @see {@link https://github.com/reduxjs/reselect#createstructuredselectorinputselectors-selectorcreator--createselector createStructuredSelector}
*
* @public
*/
declare const createStructuredSelector: StructuredSelectorCreator;
export { CreateSelectorFunction, CreateSelectorOptions, DefaultMemoizeOptions, EqualityFn, GetParamsFromSelectors, GetStateFromSelectors, OutputParametricSelector, OutputSelector, OutputSelectorFields, ParametricSelector, Selector, SelectorArray, SelectorResultArray, StructuredSelectorCreator, createSelector, createSelectorCreator, createStructuredSelector, defaultEqualityCheck, defaultMemoize, setInputStabilityCheckEnabled, autotrackMemoize as unstable_autotrackMemoize, weakMapMemoize };
/**
* Creates a tree of `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.
*
* __Design Tradeoffs for `weakmapMemoize`:__
* - 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`s.
* - Cons:
* - There's currently no way to alter the argument comparisons.
* They're based on strict reference equality.
* - It's roughly the same speed as `defaultMemoize`, although likely a fraction slower.
*
* __Use Cases for `weakmapMemoize`:__
* - 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, props.category))
* ```
* @param func - The function to be memoized.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @example
* <caption>Using `createSelector`</caption>
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* const selectTodoById = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState, id: number) => id
* ],
* (todos) => todos[id],
* { memoize: weakMapMemoize }
* )
* ```
*
* @example
* <caption>Using `createSelectorCreator`</caption>
* ```ts
* import { createSelectorCreator, weakMapMemoize } from 'reselect'
*
* const createSelectorWeakmap = createSelectorCreator(weakMapMemoize)
*
* const selectTodoById = createSelectorWeakmap(
* [
* (state: RootState) => state.todos,
* (state: RootState, id: number) => id
* ],
* (todos) => todos[id]
* )
* ```
*
* @template Func - The type of the function that is memoized.
*
* @since 5.0.0
* @public
* @experimental
*/
declare function weakMapMemoize<Func extends AnyFunction>(func: Func): Func & {
clearCache: () => void;
};
export { Combiner, CreateSelectorFunction, CreateSelectorOptions, DefaultMemoizeOptions, EqualityFn, GetParamsFromSelectors, GetStateFromSelectors, OutputParametricSelector, OutputSelector, OutputSelectorFields, ParametricSelector, Selector, SelectorArray, SelectorResultArray, StabilityCheckFrequency, StructuredSelectorCreator, TypedStructuredSelectorCreator, createSelector, createSelectorCreator, createStructuredSelector, defaultEqualityCheck, defaultMemoize, setInputStabilityCheckEnabled, autotrackMemoize as unstable_autotrackMemoize, weakMapMemoize };

284

dist/reselect.legacy-esm.js

@@ -22,9 +22,59 @@ var __defProp = Object.defineProperty;

// src/autotrackMemoize/utils.ts
function assert(condition, msg = "Assertion failed!") {
if (!condition) {
console.error(msg);
throw new Error(msg);
// src/utils.ts
function assertIsFunction(func, errorMessage = `expected a function, instead received ${typeof func}`) {
if (typeof func !== "function") {
throw new TypeError(errorMessage);
}
}
function assertIsObject(object, errorMessage = `expected an object, instead received ${typeof object}`) {
if (typeof object !== "object") {
throw new TypeError(errorMessage);
}
}
function assertIsArrayOfFunctions(array, errorMessage = `expected all items to be functions, instead received the following types: `) {
if (!array.every((item) => typeof item === "function")) {
const itemTypes = array.map(
(item) => typeof item === "function" ? `function ${item.name || "unnamed"}()` : typeof item
).join(", ");
throw new TypeError(`${errorMessage}[${itemTypes}]`);
}
}
var ensureIsArray = (item) => {
return Array.isArray(item) ? item : [item];
};
function getDependencies(createSelectorArgs) {
const dependencies = Array.isArray(createSelectorArgs[0]) ? createSelectorArgs[0] : createSelectorArgs;
assertIsArrayOfFunctions(
dependencies,
`createSelector expects all input-selectors to be functions, but received the following types: `
);
return dependencies;
}
function collectInputSelectorResults(dependencies, inputSelectorArgs) {
const inputSelectorResults = [];
const { length } = dependencies;
for (let i = 0; i < length; i++) {
inputSelectorResults.push(dependencies[i].apply(null, inputSelectorArgs));
}
return inputSelectorResults;
}
function runStabilityCheck(inputSelectorResultsObject, options, inputSelectorArgs) {
const { memoize, memoizeOptions } = options;
const { inputSelectorResults, inputSelectorResultsCopy } = inputSelectorResultsObject;
const createAnEmptyObject = memoize(() => ({}), ...memoizeOptions);
const areInputSelectorResultsEqual = createAnEmptyObject.apply(null, inputSelectorResults) === createAnEmptyObject.apply(null, inputSelectorResultsCopy);
if (!areInputSelectorResultsEqual) {
console.warn(
"An input selector returned a different result when passed same arguments.\nThis means your output selector will likely run more frequently than intended.\nAvoid returning a new reference inside your input selector, e.g.\n`createSelector([(arg1, arg2) => ({ arg1, arg2 })],(arg1, arg2) => {})`",
{
arguments: inputSelectorArgs,
firstInputs: inputSelectorResults,
secondInputs: inputSelectorResultsCopy
}
);
}
}
var shouldRunInputStabilityCheck = (inputStabilityCheck, firstRun) => {
return inputStabilityCheck === "always" || inputStabilityCheck === "once" && firstRun;
};

@@ -105,6 +155,7 @@ // src/autotrackMemoize/autotracking.ts

function setValue(storage, value) {
assert(
storage instanceof Cell,
"setValue must be passed a tracked store created with `createStorage`."
);
if (!(storage instanceof Cell)) {
throw new TypeError(
"setValue must be passed a tracked store created with `createStorage`."
);
}
storage.value = storage._lastValue = value;

@@ -116,4 +167,4 @@ }

function createCache(fn) {
assert(
typeof fn === "function",
assertIsFunction(
fn,
"the first parameter to `createCache` must be a function"

@@ -402,3 +453,5 @@ );

}
memoized.clearCache = () => cache.clear();
memoized.clearCache = () => {
cache.clear();
};
return memoized;

@@ -429,113 +482,2 @@ }

// src/weakMapMemoize.ts
var UNTERMINATED = 0;
var TERMINATED = 1;
function createCacheNode() {
return {
s: UNTERMINATED,
// status, represents whether the cached computation returned a value or threw an error
v: void 0,
// value, either the cached result or an error, depending on s
o: null,
// object cache, a WeakMap where non-primitive arguments are stored
p: null
// primitive cache, a regular Map where primitive arguments are stored.
};
}
function weakMapMemoize(func) {
let fnNode = createCacheNode();
function memoized() {
let cacheNode = fnNode;
for (let i = 0, l = arguments.length; i < l; i++) {
const arg = arguments[i];
if (typeof arg === "function" || typeof arg === "object" && arg !== null) {
let objectCache = cacheNode.o;
if (objectCache === null) {
cacheNode.o = objectCache = /* @__PURE__ */ new WeakMap();
}
const objectNode = objectCache.get(arg);
if (objectNode === void 0) {
cacheNode = createCacheNode();
objectCache.set(arg, cacheNode);
} else {
cacheNode = objectNode;
}
} else {
let primitiveCache = cacheNode.p;
if (primitiveCache === null) {
cacheNode.p = primitiveCache = /* @__PURE__ */ new Map();
}
const primitiveNode = primitiveCache.get(arg);
if (primitiveNode === void 0) {
cacheNode = createCacheNode();
primitiveCache.set(arg, cacheNode);
} else {
cacheNode = primitiveNode;
}
}
}
if (cacheNode.s === TERMINATED) {
return cacheNode.v;
}
const result = func.apply(null, arguments);
const terminatedNode = cacheNode;
terminatedNode.s = TERMINATED;
terminatedNode.v = result;
return result;
}
memoized.clearCache = () => {
fnNode = createCacheNode();
};
return memoized;
}
// src/utils.ts
function assertIsFunction(func, errorMessage = `expected a function, instead received ${typeof func}`) {
if (typeof func !== "function") {
throw new TypeError(errorMessage);
}
}
var ensureIsArray = (item) => {
return Array.isArray(item) ? item : [item];
};
function getDependencies(createSelectorArgs) {
const dependencies = Array.isArray(createSelectorArgs[0]) ? createSelectorArgs[0] : createSelectorArgs;
if (!dependencies.every((dep) => typeof dep === "function")) {
const dependencyTypes = dependencies.map(
(dep) => typeof dep === "function" ? `function ${dep.name || "unnamed"}()` : typeof dep
).join(", ");
throw new TypeError(
`createSelector expects all input-selectors to be functions, but received the following types: [${dependencyTypes}]`
);
}
return dependencies;
}
function collectInputSelectorResults(dependencies, inputSelectorArgs) {
const inputSelectorResults = [];
const { length } = dependencies;
for (let i = 0; i < length; i++) {
inputSelectorResults.push(dependencies[i].apply(null, inputSelectorArgs));
}
return inputSelectorResults;
}
function runStabilityCheck(inputSelectorResultsObject, options, inputSelectorArgs) {
const { memoize, memoizeOptions } = options;
const { inputSelectorResults, inputSelectorResultsCopy } = inputSelectorResultsObject;
const createAnEmptyObject = memoize(() => ({}), ...memoizeOptions);
const areInputSelectorResultsEqual = createAnEmptyObject.apply(null, inputSelectorResults) === createAnEmptyObject.apply(null, inputSelectorResultsCopy);
if (!areInputSelectorResultsEqual) {
console.warn(
"An input selector returned a different result when passed same arguments.\nThis means your output selector will likely run more frequently than intended.\nAvoid returning a new reference inside your input selector, e.g.\n`createSelector([(arg1, arg2) => ({ arg1, arg2 })],(arg1, arg2) => {})`",
{
arguments: inputSelectorArgs,
firstInputs: inputSelectorResults,
secondInputs: inputSelectorResultsCopy
}
);
}
}
var shouldRunInputStabilityCheck = (inputStabilityCheck, firstRun) => {
return inputStabilityCheck === "always" || inputStabilityCheck === "once" && firstRun;
};
// src/createSelectorCreator.ts

@@ -551,10 +493,10 @@ var globalStabilityCheck = "once";

} : memoizeOrOptions;
const createSelector2 = (...funcs) => {
const createSelector2 = (...createSelectorArgs) => {
let recomputations = 0;
let lastResult;
let directlyPassedOptions = {};
let resultFunc = funcs.pop();
let resultFunc = createSelectorArgs.pop();
if (typeof resultFunc === "object") {
directlyPassedOptions = resultFunc;
resultFunc = funcs.pop();
resultFunc = createSelectorArgs.pop();
}

@@ -575,3 +517,3 @@ assertIsFunction(

const finalArgsMemoizeOptions = ensureIsArray(argsMemoizeOptions);
const dependencies = getDependencies(funcs);
const dependencies = getDependencies(createSelectorArgs);
const memoizedResultFunc = memoize(function recomputationWrapper() {

@@ -622,14 +564,14 @@ recomputations++;

// src/createStructuredSelector.ts
var createStructuredSelector = (selectors, selectorCreator = createSelector) => {
if (typeof selectors !== "object") {
throw new TypeError(
`createStructuredSelector expects first argument to be an object where each property is a selector, instead received a ${typeof selectors}`
);
}
const objectKeys = Object.keys(selectors);
const resultSelector = selectorCreator(
objectKeys.map((key) => selectors[key]),
(...values) => {
return values.reduce((composition, value, index) => {
composition[objectKeys[index]] = value;
var createStructuredSelector = (inputSelectorsObject, selectorCreator = createSelector) => {
assertIsObject(
inputSelectorsObject,
`createStructuredSelector expects first argument to be an object where each property is a selector, instead received a ${typeof inputSelectorsObject}`
);
const inputSelectorKeys = Object.keys(inputSelectorsObject);
const dependencies = inputSelectorKeys.map((key) => inputSelectorsObject[key]);
const structuredSelector = selectorCreator(
dependencies,
(...inputSelectorResults) => {
return inputSelectorResults.reduce((composition, value, index) => {
composition[inputSelectorKeys[index]] = value;
return composition;

@@ -639,4 +581,66 @@ }, {});

);
return resultSelector;
return structuredSelector;
};
// src/weakMapMemoize.ts
var UNTERMINATED = 0;
var TERMINATED = 1;
function createCacheNode() {
return {
s: UNTERMINATED,
// status, represents whether the cached computation returned a value or threw an error
v: void 0,
// value, either the cached result or an error, depending on s
o: null,
// object cache, a WeakMap where non-primitive arguments are stored
p: null
// primitive cache, a regular Map where primitive arguments are stored.
};
}
function weakMapMemoize(func) {
let fnNode = createCacheNode();
function memoized() {
let cacheNode = fnNode;
for (let i = 0, l = arguments.length; i < l; i++) {
const arg = arguments[i];
if (typeof arg === "function" || typeof arg === "object" && arg !== null) {
let objectCache = cacheNode.o;
if (objectCache === null) {
cacheNode.o = objectCache = /* @__PURE__ */ new WeakMap();
}
const objectNode = objectCache.get(arg);
if (objectNode === void 0) {
cacheNode = createCacheNode();
objectCache.set(arg, cacheNode);
} else {
cacheNode = objectNode;
}
} else {
let primitiveCache = cacheNode.p;
if (primitiveCache === null) {
cacheNode.p = primitiveCache = /* @__PURE__ */ new Map();
}
const primitiveNode = primitiveCache.get(arg);
if (primitiveNode === void 0) {
cacheNode = createCacheNode();
primitiveCache.set(arg, cacheNode);
} else {
cacheNode = primitiveNode;
}
}
}
if (cacheNode.s === TERMINATED) {
return cacheNode.v;
}
const result = func.apply(null, arguments);
const terminatedNode = cacheNode;
terminatedNode.s = TERMINATED;
terminatedNode.v = result;
return result;
}
memoized.clearCache = () => {
fnNode = createCacheNode();
};
return memoized;
}
export {

@@ -643,0 +647,0 @@ createSelector,

{
"name": "reselect",
"version": "5.0.0-beta.0",
"version": "5.0.0-beta.1",
"description": "Selectors for Redux.",

@@ -30,2 +30,3 @@ "main": "./dist/cjs/reselect.cjs",

"prepack": "yarn build",
"bench": "vitest --run bench",
"test": "node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js run",

@@ -32,0 +33,0 @@ "test:cov": "vitest run --coverage",

@@ -534,2 +534,13 @@ # Reselect

Conceptually, Reselect works like this internally:
```ts
const finalSelector = (...args) => {
const extractedValues = inputFunctions.map(input => input(...args));
return output(...extractedValues);
}
```
In other words, all the arguments passed to the selector function are immediately passed to all of the inputs.
As shown in the API reference section above, provide input selectors that extract the arguments and forward them to the output selector for calculation:

@@ -550,2 +561,5 @@

More generally, you can have N arguments passed to the selector, and you can have M input functions extracting values from any of those arguments. All M extracted values get passed to the output function.
### Q: The default memoization function is no good, can I use a different one?

@@ -552,0 +566,0 @@

@@ -7,3 +7,3 @@ // Original autotracking implementation source:

import type { EqualityFn } from '@internal/types'
import { assert } from './utils'
import { assertIsFunction } from '@internal/utils'

@@ -137,6 +137,7 @@ // The global revision clock. Every time state changes, the clock increments.

): void {
assert(
storage instanceof Cell,
'setValue must be passed a tracked store created with `createStorage`.'
)
if (!(storage instanceof Cell)) {
throw new TypeError(
'setValue must be passed a tracked store created with `createStorage`.'
)
}

@@ -154,4 +155,4 @@ storage.value = storage._lastValue = value

export function createCache<T = unknown>(fn: () => T): TrackingCache {
assert(
typeof fn === 'function',
assertIsFunction(
fn,
'the first parameter to `createCache` must be a function'

@@ -158,0 +159,0 @@ )

@@ -11,3 +11,64 @@ import { createNode, updateNode } from './proxy'

export function autotrackMemoize<F extends AnyFunction>(func: F) {
/**
* Uses an "auto-tracking" approach inspired by the work of the Ember Glimmer team.
* It uses a Proxy to wrap arguments and track accesses to nested fields
* in your selector on first read. Later, when the selector is called with
* new arguments, it identifies which accessed fields have changed and
* only recalculates the result if one or more of those accessed fields have changed.
* This allows it to be more precise than the shallow equality checks in `defaultMemoize`.
*
* __Design Tradeoffs for `autotrackMemoize`:__
* - Pros:
* - It is likely to avoid excess calculations and recalculate fewer times than `defaultMemoize` will,
* which may also result in fewer component re-renders.
* - Cons:
* - It only has a cache size of 1.
* - It is slower than `defaultMemoize`, 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)
* - It can have some unexpected behavior. Because it tracks nested field accesses,
* cases where you don't access a field will not recalculate properly.
* For example, a badly-written selector like:
* ```ts
* createSelector([state => state.todos], todos => todos)
* ```
* that just immediately returns the extracted value will never update, because it doesn't see any field accesses to check.
*
* __Use Cases for `autotrackMemoize`:__
* - It is likely best used for cases where you need to access specific nested fields
* in data, and avoid recalculating if other fields in the same data objects are immutably updated.
*
* @param func - The function to be memoized.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @example
* <caption>Using `createSelector`</caption>
* ```ts
* import { unstable_autotrackMemoize as autotrackMemoize, createSelector } from 'reselect'
*
* const selectTodoIds = createSelector(
* [(state: RootState) => state.todos],
* (todos) => todos.map(todo => todo.id),
* { memoize: autotrackMemoize }
* )
* ```
*
* @example
* <caption>Using `createSelectorCreator`</caption>
* ```ts
* import { unstable_autotrackMemoize as autotrackMemoize, createSelectorCreator } from 'reselect'
*
* const createSelectorAutotrack = createSelectorCreator(autotrackMemoize)
*
* const selectTodoIds = createSelectorAutotrack(
* [(state: RootState) => state.todos],
* (todos) => todos.map(todo => todo.id)
* )
* ```
*
* @template Func - The type of the function that is memoized.
*
* @since 5.0.0
* @public
* @experimental
*/
export function autotrackMemoize<Func extends AnyFunction>(func: Func) {
// we reference arguments instead of spreading them for performance reasons

@@ -38,3 +99,3 @@

return memoized as F & { clearCache: () => void }
return memoized as Func & { clearCache: () => void }
}

@@ -0,1 +1,2 @@

import type { OutputSelector, Selector, SelectorArray } from 'reselect'
import { defaultMemoize } from './defaultMemoize'

@@ -10,5 +11,3 @@

GetStateFromSelectors,
OutputSelector,
Selector,
SelectorArray,
InterruptRecursion,
StabilityCheckFrequency,

@@ -32,5 +31,7 @@ UnknownMemoizer

* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @public
*/
export interface CreateSelectorFunction<
MemoizeFunction extends UnknownMemoizer,
MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize

@@ -42,3 +43,3 @@ > {

* @param createSelectorArgs - An arbitrary number of input selectors as separate inline arguments and a `combiner` function.
* @returns An output selector.
* @returns A memoized output selector.
*

@@ -49,2 +50,4 @@ * @template InputSelectors - The type of the input selectors as an array.

* @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`.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions createSelector}
*/

@@ -61,3 +64,4 @@ <InputSelectors extends SelectorArray, Result>(

ArgsMemoizeFunction
>
> &
InterruptRecursion

@@ -68,3 +72,3 @@ /**

* @param createSelectorArgs - An arbitrary number of input selectors as separate inline arguments, a `combiner` function and an `options` object.
* @returns An output selector.
* @returns A memoized output selector.
*

@@ -75,2 +79,4 @@ * @template InputSelectors - The type of the input selectors as an array.

* @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`.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions createSelector}
*/

@@ -100,3 +106,4 @@ <

OverrideArgsMemoizeFunction
>
> &
InterruptRecursion

@@ -109,3 +116,3 @@ /**

* @param createSelectorOptions - An optional options object that allows for further customization per selector.
* @returns An output selector.
* @returns A memoized output selector.
*

@@ -116,2 +123,4 @@ * @template InputSelectors - The type of the input selectors array.

* @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`.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions createSelector}
*/

@@ -139,3 +148,4 @@ <

OverrideArgsMemoizeFunction
>
> &
InterruptRecursion
}

@@ -163,2 +173,4 @@

* import { setInputStabilityCheckEnabled } from 'reselect'
import { assert } from './autotrackMemoize/utils';
import { OutputSelectorFields, Mapped } from './types';
*

@@ -176,2 +188,5 @@ * // Run only the first time the selector is called. (default)

* @see {@link https://github.com/reduxjs/reselect#global-configuration global-configuration}
*
* @since 5.0.0
* @public
*/

@@ -211,2 +226,7 @@ export function setInputStabilityCheckEnabled(

* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorcreatormemoize-memoizeoptions createSelectorCreator}
*
* @since 5.0.0
* @public
*/

@@ -218,5 +238,5 @@ export function createSelectorCreator<

options: CreateSelectorOptions<
typeof defaultMemoize,
typeof defaultMemoize,
MemoizeFunction,
typeof defaultMemoize,
never,
ArgsMemoizeFunction

@@ -248,2 +268,6 @@ >

* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* @see {@link https://github.com/reduxjs/reselect#createselectorcreatormemoize-memoizeoptions createSelectorCreator}
*
* @public
*/

@@ -299,3 +323,3 @@ export function createSelectorCreator<MemoizeFunction extends UnknownMemoizer>(

>(
...funcs: [
...createSelectorArgs: [
...inputSelectors: [...InputSelectors],

@@ -329,3 +353,3 @@ combiner: Combiner<InputSelectors, Result>,

// Normally, the result func or "combiner" is the last arg
let resultFunc = funcs.pop() as
let resultFunc = createSelectorArgs.pop() as
| Combiner<InputSelectors, Result>

@@ -345,3 +369,3 @@ | Partial<

// and pop the real result func off
resultFunc = funcs.pop() as Combiner<InputSelectors, Result>
resultFunc = createSelectorArgs.pop() as Combiner<InputSelectors, Result>
}

@@ -376,3 +400,3 @@

const finalArgsMemoizeOptions = ensureIsArray(argsMemoizeOptions)
const dependencies = getDependencies(funcs) as InputSelectors
const dependencies = getDependencies(createSelectorArgs) as InputSelectors

@@ -393,11 +417,2 @@ const memoizedResultFunc = memoize(function recomputationWrapper() {

// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
// TODO This was changed to `memoize` in 4.0.0 ( #297 ), but I changed it back.
// The original intent was to allow customizing things like skortchmark's
// selector debugging setup.
// But, there's multiple issues:
// - We don't pass in `memoizeOptions`
// Arguments change all the time, but input values change less often.
// Most of the time shallow equality _is_ what we really want here.
// TODO Rethink this change, or find a way to expose more options?
// @ts-ignore
const selector = argsMemoize(function dependenciesChecker() {

@@ -434,3 +449,3 @@ /** Return values of input selectors which the `resultFunc` takes as arguments. */

return lastResult
}, ...finalArgsMemoizeOptions) as Selector<
}, ...finalArgsMemoizeOptions) as unknown as Selector<
GetStateFromSelectors<InputSelectors>,

@@ -464,3 +479,12 @@ Result,

/**
* Accepts one or more "input selectors" (either as separate arguments or a single array),
* a single "result function" / "combiner", and an optional options object, and
* generates a memoized selector function.
*
* @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions createSelector}
*
* @public
*/
export const createSelector =
/* #__PURE__ */ createSelectorCreator(defaultMemoize)
import { createSelector } from './createSelectorCreator'
import type { CreateSelectorFunction } from './createSelectorCreator'
import type { AnyFunction, Head, ObjValueTuple, Selector, Tail } from './types'
import type { MergeParameters } from './versionedTypes'
import type { defaultMemoize } from './defaultMemoize'
import type {
ObjectValuesToTuple,
OutputSelector,
Selector,
UnknownMemoizer
} from './types'
import { assertIsObject } from './utils'
/**
*
* @WIP
*/
type SelectorsMap<T extends SelectorsObject> = {
[Key in keyof T]: ReturnType<T[Key]>
}
// TODO: Write more type tests for `TypedStructuredSelectorCreator`.
/**
* Allows you to create a pre-typed version of {@linkcode createStructuredSelector createStructuredSelector}
* For your root state.
*
* @since 5.0.0
* @public
* @WIP
*/
export interface TypedStructuredSelectorCreator<RootState = any> {
<
InputSelectorsObject extends {
[Key in keyof RootState]: Selector<RootState, RootState[Key], []>
} = {
[Key in keyof RootState]: Selector<RootState, RootState[Key], []>
},
MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize
>(
selectors: InputSelectorsObject,
selectorCreator?: CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
>
): OutputSelector<
ObjectValuesToTuple<InputSelectorsObject>,
SelectorsMap<InputSelectorsObject>,
MemoizeFunction,
ArgsMemoizeFunction
>
}
interface SelectorsObject {
[key: string]: AnyFunction
[key: string]: Selector
}
/**
* It provides a way to create structured selectors.
* The structured selector can take multiple input selectors
* and map their output to an object with specific keys.
*
* @see {@link https://github.com/reduxjs/reselect#createstructuredselectorinputselectors-selectorcreator--createselector createStructuredSelector}
*
* @public
*/
export interface StructuredSelectorCreator {
/**
* A convenience function for a common pattern that arises when using Reselect.
* The selector passed to a `connect` decorator often just takes the
* values of its input selectors and maps them to keys in an object.
*
* @param selectorMap - A key value pair consisting of input selectors.
* @param selectorCreator - A custom selector creator function. It defaults to `createSelector`.
* @returns A memoized structured selector.
*
* @example
* <caption>Modern Use Case</caption>
* ```ts
* import { createSelector, createStructuredSelector } from 'reselect'
*
* interface State {
* todos: {
* id: number
* title: string
* description: string
* completed: boolean
* }[]
* alerts: {
* id: number
* message: string
* type: 'reminder' | 'notification'
* read: boolean
* }[]
* }
*
* const state: State = {
* todos: [
* {
* id: 0,
* title: 'Buy groceries',
* description: 'Milk, bread, eggs, and fruits',
* completed: false
* },
* {
* id: 1,
* title: 'Schedule dentist appointment',
* description: 'Check available slots for next week',
* completed: true
* }
* ],
* alerts: [
* {
* id: 0,
* message: 'You have an upcoming meeting at 3 PM.',
* type: 'reminder',
* read: false
* },
* {
* id: 1,
* message: 'New software update available.',
* type: 'notification',
* read: true
* }
* ]
* }
*
* // This:
* const structuredSelector = createStructuredSelector(
* {
* allTodos: (state: State) => state.todos,
* allAlerts: (state: State) => state.alerts,
* selectedTodo: (state: State, id: number) => state.todos[id]
* },
* createSelector
* )
*
* // Is essentially the same as this:
* const selector = createSelector(
* [
* (state: State) => state.todos,
* (state: State) => state.alerts,
* (state: State, id: number) => state.todos[id]
* ],
* (allTodos, allAlerts, selectedTodo) => {
* return {
* allTodos,
* allAlerts,
* selectedTodo
* }
* }
* )
* ```
*
* @example
* <caption>Simple Use Case</caption>
* ```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) => ({
* a,
* b
* }))
*
* const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
* ```
*
* @template InputSelectorsObject - The shape of the input selectors object.
* @template MemoizeFunction - The type of the memoize function that is used to create the structured selector. It defaults to `defaultMemoize`.
* @template ArgsMemoizeFunction - The type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `defaultMemoize`.
*
* @see {@link https://github.com/reduxjs/reselect#createstructuredselectorinputselectors-selectorcreator--createselector createStructuredSelector}
*/
<
SelectorMap extends SelectorsObject,
SelectorParams = MergeParameters<ObjValueTuple<SelectorMap>>
InputSelectorsObject extends SelectorsObject,
MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize
>(
selectorMap: SelectorMap,
selectorCreator?: CreateSelectorFunction<any, any>
): (
// Accept an arbitrary number of parameters for all selectors
// The annoying head/tail bit here is because TS isn't convinced that
// the `SelectorParams` type is really an array, so we launder things.
// Plus it matches common usage anyway.
state: Head<SelectorParams>,
...params: Tail<SelectorParams>
) => {
[Key in keyof SelectorMap]: ReturnType<SelectorMap[Key]>
}
<State, Result = State>(
selectors: {
[K in keyof Result]: Selector<State, Result[K], never>
},
selectorCreator?: CreateSelectorFunction<any, any>
): Selector<State, Result, never>
selectorMap: InputSelectorsObject,
selectorCreator?: CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
>
): OutputSelector<
ObjectValuesToTuple<InputSelectorsObject>,
SelectorsMap<InputSelectorsObject>,
MemoizeFunction,
ArgsMemoizeFunction
>
// TODO: Do we need this?
/**
* Second overload
*/
// <
// State,
// Result = State,
// MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,
// ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize
// >(
// selectors: {
// [Key in keyof State]: Selector<State, State[Key], never>
// },
// selectorCreator?: CreateSelectorFunction<
// MemoizeFunction,
// ArgsMemoizeFunction
// >
// ): OutputSelector<
// readonly Selector<State, State, []>[],
// Result,
// MemoizeFunction,
// ArgsMemoizeFunction
// >
}
// Manual definition of state and output arguments
export const createStructuredSelector = ((
selectors: SelectorsObject,
selectorCreator = createSelector
/**
* A convenience function for a common pattern that arises when using Reselect.
* The selector passed to a `connect` decorator often just takes the values of its input selectors
* and maps them to keys in an object.
*
* @example
* <caption>Simple Use Case</caption>
* ```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) => ({
* a,
* b
* }))
* ```
*
* @see {@link https://github.com/reduxjs/reselect#createstructuredselectorinputselectors-selectorcreator--createselector createStructuredSelector}
*
* @public
*/
export const createStructuredSelector: StructuredSelectorCreator = (<
InputSelectorsObject extends SelectorsObject,
MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize
>(
inputSelectorsObject: InputSelectorsObject,
selectorCreator: CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
> = createSelector as CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
>
) => {
if (typeof selectors !== 'object') {
throw new TypeError(
'createStructuredSelector expects first argument to be an object ' +
`where each property is a selector, instead received a ${typeof selectors}`
)
}
const objectKeys = Object.keys(selectors)
const resultSelector = selectorCreator(
objectKeys.map(key => selectors[key]),
(...values: any[]) => {
return values.reduce((composition, value, index) => {
composition[objectKeys[index]] = value
assertIsObject(
inputSelectorsObject,
'createStructuredSelector expects first argument to be an object ' +
`where each property is a selector, instead received a ${typeof inputSelectorsObject}`
)
const inputSelectorKeys = Object.keys(inputSelectorsObject)
const dependencies = inputSelectorKeys.map(key => inputSelectorsObject[key])
const structuredSelector = selectorCreator(
dependencies,
(...inputSelectorResults: any[]) => {
return inputSelectorResults.reduce((composition, value, index) => {
composition[inputSelectorKeys[index]] = value
return composition

@@ -58,3 +271,3 @@ }, {})

)
return resultSelector
}) as unknown as StructuredSelectorCreator
return structuredSelector
}) as StructuredSelectorCreator

@@ -90,2 +90,5 @@ import type { AnyFunction, EqualityFn } from './types'

/**
* @public
*/
export const defaultEqualityCheck: EqualityFn = (a, b): boolean => {

@@ -116,5 +119,27 @@ return a === b

/**
* @public
*/
export interface DefaultMemoizeOptions {
/**
* Used to compare the individual arguments of the provided calculation function.
*
* @default defaultEqualityCheck
*/
equalityCheck?: EqualityFn
/**
* 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
* ```ts
* todos.map(todo => todo.id)
* ```
* 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.
*/
resultEqualityCheck?: EqualityFn
/**
* The cache size for the selector. If greater than 1, the selector will use an LRU cache internally.
*
* @default 1
*/
maxSize?: number

@@ -125,4 +150,16 @@ }

// and optional comparison of the result value with existing values
export function defaultMemoize<F extends AnyFunction>(
func: F,
/**
* The standard memoize function used by `createSelector`.
* @param func - The function to be memoized.
* @param equalityCheckOrOptions - Either an equality check function or an options object.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @template Func - The type of the function that is memoized.
*
* @see {@link https://github.com/reduxjs/reselect#defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck defaultMemoize}
*
* @public
*/
export function defaultMemoize<Func extends AnyFunction>(
func: Func,
equalityCheckOrOptions?: EqualityFn | DefaultMemoizeOptions

@@ -171,5 +208,7 @@ ) {

memoized.clearCache = () => cache.clear()
memoized.clearCache = () => {
cache.clear()
}
return memoized as F & { clearCache: () => void }
return memoized as Func & { clearCache: () => void }
}

@@ -0,2 +1,17 @@

export { autotrackMemoize as unstable_autotrackMemoize } from './autotrackMemoize/autotrackMemoize'
export {
createSelector,
createSelectorCreator,
setInputStabilityCheckEnabled
} from './createSelectorCreator'
export type { CreateSelectorFunction } from './createSelectorCreator'
export { createStructuredSelector } from './createStructuredSelector'
export type {
StructuredSelectorCreator,
TypedStructuredSelectorCreator
} from './createStructuredSelector'
export { defaultEqualityCheck, defaultMemoize } from './defaultMemoize'
export type { DefaultMemoizeOptions } from './defaultMemoize'
export type {
Combiner,
CreateSelectorOptions,

@@ -12,20 +27,5 @@ EqualityFn,

SelectorArray,
SelectorResultArray
SelectorResultArray,
StabilityCheckFrequency
} from './types'
export { autotrackMemoize as unstable_autotrackMemoize } from './autotrackMemoize/autotrackMemoize'
export { weakMapMemoize } from './weakMapMemoize'
export { defaultEqualityCheck, defaultMemoize } from './defaultMemoize'
export type { DefaultMemoizeOptions } from './defaultMemoize'
export {
createSelector,
createSelectorCreator,
setInputStabilityCheckEnabled
} from './createSelectorCreator'
export type { CreateSelectorFunction } from './createSelectorCreator'
export { createStructuredSelector } from './createStructuredSelector'
export type { StructuredSelectorCreator } from './createStructuredSelector'

@@ -7,23 +7,24 @@ import type { defaultMemoize } from './defaultMemoize'

/*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
* Reselect Data Types
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*/
/**
* A standard selector function, which takes three generic type arguments:
* @template State - The first value, often a Redux root state object
* @template Result - The final result returned by the selector
* @template Params - All additional arguments passed into the selector
* A standard selector function.
* @template State - The first value, often a Redux root state object.
* @template Result - The final result returned by the selector.
* @template Params - All additional arguments passed into the selector.
*
* @public
*/
export type Selector<
// The state can be anything
State = any,
// The result will be inferred
Result = unknown,
// There are either 0 params, or N params
Params extends readonly any[] = any[]
// If there are 0 params, type the function as just State in, Result out.
// Otherwise, type it as State + Params in, Result out.
> =
> = Distribute<
/**

@@ -37,18 +38,131 @@ * A function that takes a state and returns data that is based on that state.

(state: State, ...params: FallbackIfNever<Params, []>) => Result
>
/**
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
* An array of input selectors.
*
* @template InputSelectors - An array of input selectors.
* @template Result - Result returned by `resultFunc`.
* @public
*/
export type Combiner<InputSelectors extends SelectorArray, Result> =
export type SelectorArray = readonly Selector[]
/**
* Extracts an array of all return types from all input selectors.
*
* @public
*/
export type SelectorResultArray<Selectors extends SelectorArray> =
ExtractReturnType<Selectors>
/**
* The options object used inside `createSelector` and `createSelectorCreator`.
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
* @template OverrideMemoizeFunction - The type of the optional `memoize` function that could be passed into the options object inside `createSelector` to override the original `memoize` function that was initially passed into `createSelectorCreator`.
* @template OverrideArgsMemoizeFunction - The type of the optional `argsMemoize` function that could be passed into the options object inside `createSelector` to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`. If none was initially provided, `defaultMemoize` will be used.
*
* @public
*/
export interface CreateSelectorOptions<
MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,
OverrideMemoizeFunction extends UnknownMemoizer = never,
OverrideArgsMemoizeFunction extends UnknownMemoizer = never
> {
/**
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
* Overrides the global input stability check for the selector.
* - `once` - Run only the first time the selector is called.
* - `always` - Run every time the selector is called.
* - `never` - Never run the input stability check.
*
* @param resultFuncArgs - Return values of input selectors.
* @returns The return value of {@linkcode OutputSelectorFields.resultFunc resultFunc}.
* @default 'once'
*
* @see {@link https://github.com/reduxjs/reselect#development-only-checks development-only-checks}
* @see {@link https://github.com/reduxjs/reselect#inputstabilitycheck inputStabilityCheck}
* @see {@link https://github.com/reduxjs/reselect#per-selector-configuration per-selector-configuration}
*
* @since 5.0.0
*/
(...resultFuncArgs: SelectorResultArray<InputSelectors>) => Result
inputStabilityCheck?: StabilityCheckFrequency
/**
* The memoize function that is used to memoize the {@linkcode OutputSelectorFields.resultFunc resultFunc}
* inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `memoize` function initially passed into `createSelectorCreator`.
*
* @example
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* const selectTodoById = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState, id: number) => id
* ],
* (todos) => todos[id],
* { memoize: weakMapMemoize }
* )
* ```
*
* @since 5.0.0
*/
// If `memoize` is not provided inside the options object, fallback to `MemoizeFunction` which is the original memoize function passed into `createSelectorCreator`.
memoize: FallbackIfNever<OverrideMemoizeFunction, MemoizeFunction>
/**
* The optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `argsMemoize` function initially passed into `createSelectorCreator`. If none was initially provided, `defaultMemoize` will be used.
*
* @example
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* const selectTodoById = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState, id: number) => id
* ],
* (todos) => todos[id],
* { argsMemoize: weakMapMemoize }
* )
* ```
*
* @default defaultMemoize
*
* @since 5.0.0
*/
// If `argsMemoize` is not provided inside the options object,
// fallback to `ArgsMemoizeFunction` which is the original `argsMemoize` function passed into `createSelectorCreator`.
// If none was passed originally to `createSelectorCreator`, it should fallback to `defaultMemoize`.
argsMemoize?: FallbackIfNever<
OverrideArgsMemoizeFunction,
ArgsMemoizeFunction
>
/**
* Optional configuration options for the {@linkcode CreateSelectorOptions.memoize memoize} function.
* These options are passed to the {@linkcode CreateSelectorOptions.memoize memoize} function as the second argument.
*
* @since 5.0.0
*/
// Should dynamically change to the options argument of `memoize`.
memoizeOptions?: OverrideMemoizeOptions<
MemoizeFunction,
OverrideMemoizeFunction
>
/**
* Optional configuration options for the {@linkcode CreateSelectorOptions.argsMemoize argsMemoize} function.
* These options are passed to the {@linkcode CreateSelectorOptions.argsMemoize argsMemoize} function as the second argument.
*
* @since 5.0.0
*/
argsMemoizeOptions?: OverrideMemoizeOptions<
ArgsMemoizeFunction,
OverrideArgsMemoizeFunction
>
}
/**

@@ -69,4 +183,6 @@ * The additional fields attached to the output selector generated by `createSelector`.

* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @public
*/
export interface OutputSelectorFields<
export type OutputSelectorFields<
InputSelectors extends SelectorArray = SelectorArray,

@@ -76,11 +192,6 @@ Result = unknown,

ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize
> extends Required<
Pick<
CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction>,
'argsMemoize' | 'memoize'
>
> {
/** The final function passed to `createSelector`. Otherwise known as the `combiner`. */
> = {
/** The final function passed to `createSelector`. Otherwise known as the `combiner`.*/
resultFunc: Combiner<InputSelectors, Result>
/** The memoized version of {@linkcode resultFunc resultFunc}. */
/** The memoized version of {@linkcode OutputSelectorFields.resultFunc resultFunc}. */
memoizedResultFunc: Combiner<InputSelectors, Result> &

@@ -96,3 +207,10 @@ ExtractMemoizerFields<MemoizeFunction>

resetRecomputations: () => 0
}
} & Simplify<
Required<
Pick<
CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction>,
'argsMemoize' | 'memoize'
>
>
>

@@ -106,2 +224,4 @@ /**

* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @public
*/

@@ -113,50 +233,38 @@ export type OutputSelector<

ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize
> = PrepareOutputSelector<
InputSelectors,
> = Selector<
GetStateFromSelectors<InputSelectors>,
Result,
MemoizeFunction,
ArgsMemoizeFunction
GetParamsFromSelectors<InputSelectors>
> &
ExtractMemoizerFields<ArgsMemoizeFunction>
ExtractMemoizerFields<ArgsMemoizeFunction> &
OutputSelectorFields<
InputSelectors,
Result,
MemoizeFunction,
ArgsMemoizeFunction
>
/**
* A helper type designed to optimize TypeScript performance by composing parts of {@linkcode OutputSelector OutputSelector} in a more statically structured manner.
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
*
* This is achieved by utilizing the `extends` keyword with `interfaces`, as opposed to creating intersections with type aliases.
* This approach offers some performance benefits:
* - `Interfaces` create a flat object type, while intersections with type aliases recursively merge properties.
* - Type relationships between `interfaces` are also cached, as opposed to intersection types as a whole.
* - When checking against an intersection type, every constituent is verified before checking against the "effective" flattened type.
* @template InputSelectors - An array of input selectors.
* @template Result - Result returned by `resultFunc`.
*
* This optimization focuses on resolving much of the type composition for
* {@linkcode OutputSelector OutputSelector} using `extends` with `interfaces`,
* rather than relying on intersections for the entire {@linkcode OutputSelector OutputSelector}.
*
* @template InputSelectors - The type of the input selectors.
* @template Result - The type of the result returned by the `resultFunc`.
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
*
* @see {@link https://github.com/microsoft/TypeScript/wiki/Performance#preferring-interfaces-over-intersections Reference}
* @public
*/
export interface PrepareOutputSelector<
InputSelectors extends SelectorArray = SelectorArray,
Result = unknown,
MemoizeFunction extends UnknownMemoizer = typeof defaultMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof defaultMemoize
> extends OutputSelectorFields<
InputSelectors,
Result,
MemoizeFunction,
ArgsMemoizeFunction
>,
Selector<
GetStateFromSelectors<InputSelectors>,
Result,
GetParamsFromSelectors<InputSelectors>
> {}
export type Combiner<InputSelectors extends SelectorArray, Result> = Distribute<
/**
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
*
* @param resultFuncArgs - Return values of input selectors.
* @returns The return value of {@linkcode OutputSelectorFields.resultFunc resultFunc}.
*/
(...resultFuncArgs: SelectorResultArray<InputSelectors>) => Result
>
/**
* A selector that is assumed to have one additional argument, such as
* the props from a React component
* the props from a React component.
*
* @public
*/

@@ -169,3 +277,7 @@ export type ParametricSelector<State, Props, Result> = Selector<

/** A generated selector that is assumed to have one additional argument */
/**
* A generated selector that is assumed to have one additional argument.
*
* @public
*/
export type OutputParametricSelector<State, Props, Result> = ParametricSelector<

@@ -178,119 +290,70 @@ State,

/** An array of input selectors */
export type SelectorArray = ReadonlyArray<Selector>
/** A standard function returning true if two values are considered equal */
/**
* A standard function returning true if two values are considered equal.
*
* @public
*/
export type EqualityFn = (a: any, b: any) => boolean
export type StabilityCheckFrequency = 'always' | 'once' | 'never'
/**
* The options object used inside `createSelector` and `createSelectorCreator`.
* The frequency of input stability checks.
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
* @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., `defaultMemoize` or `weakMapMemoize`). If none is explicitly provided, `defaultMemoize` will be used.
* @template OverrideMemoizeFunction - The type of the optional `memoize` function that could be passed into the options object inside `createSelector` to override the original `memoize` function that was initially passed into `createSelectorCreator`.
* @template OverrideArgsMemoizeFunction - The type of the optional `argsMemoize` function that could be passed into the options object inside `createSelector` to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`. If none was initially provided, `defaultMemoize` will be used.
* @since 5.0.0
* @public
*/
export interface CreateSelectorOptions<
MemoizeFunction extends UnknownMemoizer,
ArgsMemoizeFunction extends UnknownMemoizer,
OverrideMemoizeFunction extends UnknownMemoizer = never,
OverrideArgsMemoizeFunction extends UnknownMemoizer = never
> {
/**
* Overrides the global input stability check for the selector.
* - `once` - Run only the first time the selector is called.
* - `always` - Run every time the selector is called.
* - `never` - Never run the input stability check.
*
* @default 'once'
*
* @see {@link https://github.com/reduxjs/reselect#development-only-checks development-only-checks}
* @see {@link https://github.com/reduxjs/reselect#inputstabilitycheck inputStabilityCheck}
* @see {@link https://github.com/reduxjs/reselect#per-selector-configuration per-selector-configuration}
*/
inputStabilityCheck?: StabilityCheckFrequency
export type StabilityCheckFrequency = 'always' | 'once' | 'never'
/**
* The memoize function that is used to memoize the {@linkcode OutputSelectorFields.resultFunc resultFunc}
* inside `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `memoize` function initially passed into `createSelectorCreator`.
*/
// If `memoize` is not provided inside the options object, fallback to `MemoizeFunction` which is the original memoize function passed into `createSelectorCreator`.
memoize: FallbackIfNever<OverrideMemoizeFunction, MemoizeFunction>
/**
* The optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `defaultMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `argsMemoize` function initially passed into `createSelectorCreator`. If none was initially provided, `defaultMemoize` will be used.
*
* @default defaultMemoize
*/
// If `argsMemoize` is not provided inside the options object,
// fallback to `ArgsMemoizeFunction` which is the original `argsMemoize` function passed into `createSelectorCreator`.
// If none was passed originally to `createSelectorCreator`, it should fallback to `defaultMemoize`.
argsMemoize?: FallbackIfNever<
OverrideArgsMemoizeFunction,
ArgsMemoizeFunction
>
/**
* Optional configuration options for the {@linkcode memoize memoize} function.
* These options are passed to the {@linkcode memoize memoize} function as the second argument.
*/
// Should dynamically change to the options argument of `memoize`.
memoizeOptions?: OverrideMemoizeOptions<
MemoizeFunction,
OverrideMemoizeFunction
>
/**
* Optional configuration options for the {@linkcode argsMemoize argsMemoize} function.
* These options are passed to the {@linkcode argsMemoize argsMemoize} function as the second argument.
*/
argsMemoizeOptions?: OverrideMemoizeOptions<
ArgsMemoizeFunction,
OverrideArgsMemoizeFunction
>
}
/*
/**
* Determines the combined single "State" type (first arg) from all input selectors.
*
* Reselect Internal Types
*
* @public
*/
/** Extracts an array of all return types from all input selectors */
export type SelectorResultArray<Selectors extends SelectorArray> =
ExtractReturnType<Selectors>
/** Determines the combined single "State" type (first arg) from all input selectors */
export type GetStateFromSelectors<Selectors extends SelectorArray> =
MergeParameters<Selectors>[0]
/** Determines the combined "Params" type (all remaining args) from all input selectors */
export type GetParamsFromSelectors<
Selectors extends SelectorArray,
RemainingItems extends readonly unknown[] = Tail<MergeParameters<Selectors>>
> = RemainingItems
/**
* Determines the combined "Params" type (all remaining args) from all input selectors.
*
* @public
*/
export type GetParamsFromSelectors<Selectors extends SelectorArray> = ArrayTail<
MergeParameters<Selectors>
>
/*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
* Reselect Internal Utility Types
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*/
/** Any function with any arguments */
/**
* Any function with any arguments.
*
* @internal
*/
export type AnyFunction = (...args: any[]) => any
/** Any function with unknown arguments */
/**
* Any function with unknown arguments.
*
* @internal
*/
export type UnknownFunction = (...args: unknown[]) => unknown
/** Any Memoizer function. A memoizer is a function that accepts another function and returns it. */
export type UnknownMemoizer<Func extends UnknownFunction = UnknownFunction> = (
func: Func,
...options: any[]
) => Func
/**
* Any Memoizer function. A memoizer is a function that accepts another function and returns it.
*
* @template FunctionType - The type of the function that is memoized.
*
* @internal
*/
export type UnknownMemoizer<
FunctionType extends UnknownFunction = UnknownFunction
> = (func: FunctionType, ...options: any[]) => FunctionType
/**
* When a generic type parameter is using its default value of `never`, fallback to a different type.

@@ -300,2 +363,4 @@ *

* @template FallbackTo - Type to fallback to if `T` resolves to `never`.
*
* @internal
*/

@@ -311,2 +376,4 @@ export type FallbackIfNever<T, FallbackTo> = IfNever<T, FallbackTo, T>

* @template OverrideMemoizeFunction - The type of the optional `memoize` or `argsMemoize` function passed directly into `createSelector` which then overrides the original `memoize` or `argsMemoize` function passed into `createSelectorCreator`.
*
* @internal
*/

@@ -323,43 +390,139 @@ export type OverrideMemoizeOptions<

/**
* Extract the memoize options from the parameters of a memoize function.
* Extracts the non-function part of a type.
*
* @template T - The input type to be refined by excluding function types and index signatures.
*
* @internal
*/
export type NonFunctionType<T> = OmitIndexSignature<Exclude<T, AnyFunction>>
/**
* Extracts the function part of a type.
*
* @template T - The input type to be refined by extracting function types.
*
* @internal
*/
export type FunctionType<T> = Extract<T, AnyFunction>
/**
* Extracts the options type for a memoization function based on its parameters.
* The first parameter of the function is expected to be the function to be memoized,
* followed by options for the memoization process.
*
* @template MemoizeFunction - The type of the memoize function to be checked.
*
* @internal
*/
export type MemoizeOptionsFromParameters<
MemoizeFunction extends UnknownMemoizer
> = DropFirstParameter<MemoizeFunction>[0] | DropFirstParameter<MemoizeFunction>
> =
| (
| Simplify<NonFunctionType<DropFirstParameter<MemoizeFunction>[0]>>
| FunctionType<DropFirstParameter<MemoizeFunction>[0]>
)
| (
| Simplify<NonFunctionType<DropFirstParameter<MemoizeFunction>[number]>>
| FunctionType<DropFirstParameter<MemoizeFunction>[number]>
)[]
/**
* Extracts the additional fields that a memoize function attaches to the function it memoizes (e.g., `clearCache`).
* Extracts the additional fields that a memoize function attaches to
* the function it memoizes (e.g., `clearCache`).
*
* @template MemoizeFunction - The type of the memoize function to be checked.
*
* @internal
*/
export type ExtractMemoizerFields<MemoizeFunction extends UnknownMemoizer> =
OmitIndexSignature<ReturnType<MemoizeFunction>>
Simplify<OmitIndexSignature<ReturnType<MemoizeFunction>>>
/** Extract the return type from all functions as a tuple */
export type ExtractReturnType<T extends readonly AnyFunction[]> = {
[index in keyof T]: T[index] extends T[number] ? ReturnType<T[index]> : never
/**
* Extracts the return type from all functions as a tuple.
*
* @internal
*/
export type ExtractReturnType<FunctionsArray extends readonly AnyFunction[]> = {
[Index in keyof FunctionsArray]: FunctionsArray[Index] extends FunctionsArray[number]
? ReturnType<FunctionsArray[Index]>
: never
}
/** First item in an array */
export type Head<T> = T extends [any, ...any[]] ? T[0] : never
/** All other items in an array */
export type Tail<A> = A extends [any, ...infer Rest] ? Rest : never
/**
* Utility type to infer the type of "all params of a function except the first",
* so we can determine what arguments a memoize function accepts.
*
* @internal
*/
export type DropFirstParameter<Func extends AnyFunction> = Func extends (
firstArg: any,
...restArgs: infer Rest
) => any
? Rest
: never
/** Extract only numeric keys from an array type */
export type AllArrayKeys<A extends readonly any[]> = A extends any
? {
[K in keyof A]: K
}[number]
/**
* Distributes over a type. It is used mostly to expand a function type
* in hover previews while preserving their original JSDoc information.
*
* If preserving JSDoc information is not a concern, you can use {@linkcode ExpandFunction ExpandFunction}.
*
* @template T The type to be distributed.
*
* @internal
*/
export type Distribute<T> = T extends T ? T : never
/**
* Extracts the type of the first element of an array or tuple.
*
* @internal
*/
export type FirstArrayElement<TArray> = TArray extends readonly [
unknown,
...unknown[]
]
? TArray[0]
: never
export type List<A = any> = ReadonlyArray<A>
/**
* Extracts the type of an array or tuple minus the first element.
*
* @internal
*/
export type ArrayTail<TArray> = TArray extends readonly [
unknown,
...infer TTail
]
? TTail
: []
export type Has<U, U1> = [U1] extends [U] ? 1 : 0
/**
* An alias for type `{}`. Represents any value that is not `null` or `undefined`.
* It is mostly used for semantic purposes to help distinguish between an
* empty object type and `{}` as they are not the same.
*
* @internal
*/
export type AnyNonNullishValue = NonNullable<unknown>
/**
* Same as {@linkcode AnyNonNullishValue AnyNonNullishValue} but aliased
* for semantic purposes. It is intended to be used in scenarios where
* a recursive type definition needs to be interrupted to ensure type safety
* and to avoid excessively deep recursion that could lead to performance issues.
*
* @internal
*/
export type InterruptRecursion = AnyNonNullishValue
/*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
* External/Copied Utility Types
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
*/

@@ -371,2 +534,4 @@

* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/if-never.d.ts Source}
*
* @internal
*/

@@ -380,3 +545,9 @@ export type IfNever<T, TypeIfNever, TypeIfNotNever> = [T] extends [never]

* This is mainly used to remove explicit `any`s from the return type of some memoizers (e.g, `microMemoize`).
*
* __Disclaimer:__ When used on an intersection of a function and an object,
* the function is erased.
*
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/omit-index-signature.d.ts Source}
*
* @internal
*/

@@ -391,4 +562,6 @@ export type OmitIndexSignature<ObjectType> = {

* The infamous "convert a union type to an intersection type" hack
* Source: https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts
* Reference: https://github.com/microsoft/TypeScript/issues/29594
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts Source}
* @see {@link https://github.com/microsoft/TypeScript/issues/29594 Reference}
*
* @internal
*/

@@ -413,29 +586,14 @@ export type UnionToIntersection<Union> =

/**
* Assorted util types for type-level conditional logic
* Source: https://github.com/KiaraGrouwstra/typical
* Code to convert a union of values into a tuple.
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
export type Bool = '0' | '1'
export interface Obj<T> {
[k: string]: T
}
export type And<A extends Bool, B extends Bool> = ({
1: { 1: '1' } & Obj<'0'>
} & Obj<Obj<'0'>>)[A][B]
type Push<T extends any[], V> = [...T, V]
export type Matches<V, T> = V extends T ? '1' : '0'
export type IsArrayType<T> = Matches<T, any[]>
export type Not<T extends Bool> = { '1': '0'; '0': '1' }[T]
export type InstanceOf<V, T> = And<Matches<V, T>, Not<Matches<T, V>>>
export type IsTuple<T extends { length: number }> = And<
IsArrayType<T>,
InstanceOf<T['length'], number>
>
/**
* Code to convert a union of values into a tuple.
* Source: https://stackoverflow.com/a/55128956/62937
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
type Push<T extends any[], V> = [...T, V]
type LastOf<T> = UnionToIntersection<

@@ -447,3 +605,8 @@ T extends any ? () => T : never

// TS4.1+
/**
* TS4.1+
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
export type TuplifyUnion<

@@ -457,5 +620,7 @@ T,

* Converts "the values of an object" into a tuple, like a type-level `Object.values()`
* Source: https://stackoverflow.com/a/68695508/62937
* @see {@link https://stackoverflow.com/a/68695508/62937 Source}
*
* @internal
*/
export type ObjValueTuple<
export type ObjectValuesToTuple<
T,

@@ -465,17 +630,54 @@ KS extends any[] = TuplifyUnion<keyof T>,

> = KS extends [infer K, ...infer KT]
? ObjValueTuple<T, KT, [...R, T[K & keyof T]]>
? ObjectValuesToTuple<T, KT, [...R, T[K & keyof T]]>
: R
/** Utility type to infer the type of "all params of a function except the first", so we can determine what arguments a memoize function accepts */
export type DropFirstParameter<Func extends AnyFunction> = Func extends (
firstArg: any,
...restArgs: infer Rest
) => any
? Rest
: never
/**
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
* Type Expansion Utilities
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
*/
/**
* Expand an item a single level, or recursively.
* Source: https://stackoverflow.com/a/69288824/62937
* Check whether `U` contains `U1`.
* @see {@link https://millsp.github.io/ts-toolbelt/modules/union_has.html Source}
*
* @internal
*/
export type Has<U, U1> = [U1] extends [U] ? 1 : 0
/**
* @internal
*/
export type Boolean2 = 0 | 1
/**
* @internal
*/
export type If2<B extends Boolean2, Then, Else = never> = B extends 1
? Then
: Else
/**
* @internal
*/
export type BuiltIn =
| Function
| Error
| Date
| { readonly [Symbol.toStringTag]: string }
| RegExp
| Generator
/**
* Expand an item a single level.
* @see {@link https://stackoverflow.com/a/69288824/62937 Source}
*
* @internal
*/
export type Expand<T> = T extends (...args: infer A) => infer R

@@ -487,2 +689,8 @@ ? (...args: Expand<A>) => Expand<R>

/**
* Expand an item recursively.
* @see {@link https://stackoverflow.com/a/69288824/62937 Source}
*
* @internal
*/
export type ExpandRecursively<T> = T extends (...args: infer A) => infer R

@@ -496,6 +704,12 @@ ? (...args: ExpandRecursively<A>) => ExpandRecursively<R>

type Identity<T> = T
/**
* @internal
*/
export type Identity<T> = T
/**
* Another form of type value expansion
* Source: https://github.com/microsoft/TypeScript/issues/35247
* @see {@link https://github.com/microsoft/TypeScript/issues/35247 Source}
*
* @internal
*/

@@ -505,7 +719,35 @@ export type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>

/**
* This utility type is primarily used to expand a function type in order to
* improve its visual display in hover previews within IDEs.
*
* __Disclaimer:__ Functions expanded using this type will not display their
* original JSDoc information in hover previews.
*
* @template FunctionType - The type of the function to be expanded.
*
* @internal
*/
export type ExpandFunction<FunctionType extends AnyFunction> =
FunctionType extends FunctionType
? (...args: Parameters<FunctionType>) => ReturnType<FunctionType>
: never
/**
* Useful to flatten the type output to improve type hints shown in editors.
* And also to transform an interface into a type to aide with assignability.
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts Source}
*
* @internal
*/
export type Simplify<T> = {
[KeyType in keyof T]: T[KeyType]
} & AnyNonNullishValue
/**
* Fully expand a type, deeply
* Source: https://github.com/millsp/ts-toolbelt (`Any.Compute`)
* @see {@link https://github.com/millsp/ts-toolbelt Any.Compute}
*
* @internal
*/
type ComputeDeep<A, Seen = never> = A extends BuiltIn
export type ComputeDeep<A, Seen = never> = A extends BuiltIn
? A

@@ -515,35 +757,15 @@ : If2<

A,
A extends Array<any>
? A extends Array<Record<Key, any>>
? Array<
{
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
} & unknown
>
A extends any[]
? A extends Record<PropertyKey, any>[]
? ({
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
} & unknown)[]
: A
: A extends ReadonlyArray<any>
? A extends ReadonlyArray<Record<Key, any>>
? ReadonlyArray<
{
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
} & unknown
>
: A extends readonly any[]
? A extends readonly Record<PropertyKey, any>[]
? readonly ({
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
} & unknown)[]
: A
: { [K in keyof A]: ComputeDeep<A[K], A | Seen> } & unknown
>
export type If2<B extends Boolean2, Then, Else = never> = B extends 1
? Then
: Else
export type Boolean2 = 0 | 1
export type Key = string | number | symbol
export type BuiltIn =
| Function
| Error
| Date
| { readonly [Symbol.toStringTag]: string }
| RegExp
| Generator

@@ -17,6 +17,6 @@ import type {

*/
export function assertIsFunction<Func extends Function>(
export function assertIsFunction<FunctionType extends Function>(
func: unknown,
errorMessage = `expected a function, instead received ${typeof func}`
): asserts func is Func {
): asserts func is FunctionType {
if (typeof func !== 'function') {

@@ -28,2 +28,45 @@ throw new TypeError(errorMessage)

/**
* Assert that the provided value is an object. If the assertion fails,
* a `TypeError` is thrown with an optional custom error message.
*
* @param object - The value to be checked.
* @param errorMessage - An optional custom error message to use if the assertion fails.
* @throws A `TypeError` if the assertion fails.
*/
export function assertIsObject<ObjectType extends Record<string, unknown>>(
object: unknown,
errorMessage = `expected an object, instead received ${typeof object}`
): asserts object is ObjectType {
if (typeof object !== 'object') {
throw new TypeError(errorMessage)
}
}
/**
* Assert that the provided array is an array of functions. If the assertion fails,
* a `TypeError` is thrown with an optional custom error message.
*
* @param array - The array to be checked.
* @param errorMessage - An optional custom error message to use if the assertion fails.
* @throws A `TypeError` if the assertion fails.
*/
export function assertIsArrayOfFunctions<FunctionType extends Function>(
array: unknown[],
errorMessage = `expected all items to be functions, instead received the following types: `
): asserts array is FunctionType[] {
if (
!array.every((item): item is FunctionType => typeof item === 'function')
) {
const itemTypes = array
.map(item =>
typeof item === 'function'
? `function ${item.name || 'unnamed'}()`
: typeof item
)
.join(', ')
throw new TypeError(`${errorMessage}[${itemTypes}]`)
}
}
/**
* Ensure that the input is an array. If it's already an array, it's returned as is.

@@ -51,18 +94,7 @@ * If it's not an array, it will be wrapped in a new array.

if (
!dependencies.every((dep): dep is Selector => typeof dep === 'function')
) {
const dependencyTypes = dependencies
.map(dep =>
typeof dep === 'function'
? `function ${dep.name || 'unnamed'}()`
: typeof dep
)
.join(', ')
assertIsArrayOfFunctions<Selector>(
dependencies,
`createSelector expects all input-selectors to be functions, but received the following types: `
)
throw new TypeError(
`createSelector expects all input-selectors to be functions, but received the following types: [${dependencyTypes}]`
)
}
return dependencies as SelectorArray

@@ -69,0 +101,0 @@ }

@@ -6,2 +6,5 @@ // This entire implementation courtesy of Anders Hjelsberg:

/**
* @internal
*/
type LongestTuple<T extends readonly unknown[][]> = T extends [

@@ -15,4 +18,10 @@ infer U extends unknown[]

/**
* @internal
*/
type MostProperties<T, U> = keyof U extends keyof T ? T : U
/**
* @internal
*/
type ElementAt<T extends unknown[], N extends keyof any> = N extends keyof T

@@ -22,2 +31,5 @@ ? T[N]

/**
* @internal
*/
type ElementsAt<T extends readonly unknown[][], N extends keyof any> = {

@@ -27,2 +39,5 @@ [K in keyof T]: ElementAt<T[K], N>

/**
* @internal
*/
type Intersect<T extends readonly unknown[]> = T extends []

@@ -34,2 +49,5 @@ ? unknown

/**
* @internal
*/
type MergeTuples<

@@ -42,2 +60,5 @@ T extends readonly unknown[][],

/**
* @internal
*/
type ExtractParameters<T extends readonly AnyFunction[]> = {

@@ -47,2 +68,5 @@ [K in keyof T]: Parameters<T[K]>

/**
* @internal
*/
export type MergeParameters<T extends readonly AnyFunction[]> =

@@ -49,0 +73,0 @@ '0' extends keyof T

@@ -34,3 +34,67 @@ // Original source:

export function weakMapMemoize<F extends AnyFunction>(func: F) {
/**
* Creates a tree of `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.
*
* __Design Tradeoffs for `weakmapMemoize`:__
* - 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`s.
* - Cons:
* - There's currently no way to alter the argument comparisons.
* They're based on strict reference equality.
* - It's roughly the same speed as `defaultMemoize`, although likely a fraction slower.
*
* __Use Cases for `weakmapMemoize`:__
* - 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, props.category))
* ```
* @param func - The function to be memoized.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @example
* <caption>Using `createSelector`</caption>
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* const selectTodoById = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState, id: number) => id
* ],
* (todos) => todos[id],
* { memoize: weakMapMemoize }
* )
* ```
*
* @example
* <caption>Using `createSelectorCreator`</caption>
* ```ts
* import { createSelectorCreator, weakMapMemoize } from 'reselect'
*
* const createSelectorWeakmap = createSelectorCreator(weakMapMemoize)
*
* const selectTodoById = createSelectorWeakmap(
* [
* (state: RootState) => state.todos,
* (state: RootState, id: number) => id
* ],
* (todos) => todos[id]
* )
* ```
*
* @template Func - The type of the function that is memoized.
*
* @since 5.0.0
* @public
* @experimental
*/
export function weakMapMemoize<Func extends AnyFunction>(func: Func) {
// we reference arguments instead of spreading them for performance reasons

@@ -91,3 +155,3 @@

return memoized as F & { clearCache: () => void }
return memoized as Func & { clearCache: () => void }
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc