@reduxjs/toolkit
Advanced tools
Comparing version 2.2.3 to 2.2.4
@@ -45,3 +45,3 @@ import type { Dispatch, UnknownAction } from 'redux'; | ||
state?: unknown; | ||
dispatch?: Dispatch; | ||
dispatch?: ThunkDispatch<unknown, unknown, UnknownAction>; | ||
extra?: unknown; | ||
@@ -103,3 +103,3 @@ rejectValue?: unknown; | ||
*/ | ||
export type AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig extends AsyncThunkConfig> = (dispatch: GetDispatch<ThunkApiConfig>, getState: () => GetState<ThunkApiConfig>, extra: GetExtra<ThunkApiConfig>) => SafePromise<ReturnType<AsyncThunkFulfilledActionCreator<Returned, ThunkArg>> | ReturnType<AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>>> & { | ||
export type AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig extends AsyncThunkConfig> = (dispatch: NonNullable<GetDispatch<ThunkApiConfig>>, getState: () => GetState<ThunkApiConfig>, extra: GetExtra<ThunkApiConfig>) => SafePromise<ReturnType<AsyncThunkFulfilledActionCreator<Returned, ThunkArg>> | ReturnType<AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>>> & { | ||
abort: (reason?: string) => void; | ||
@@ -106,0 +106,0 @@ requestId: string; |
@@ -244,3 +244,3 @@ import type { Action, UnknownAction, Reducer } from 'redux'; | ||
*/ | ||
export type SliceCaseReducers<State> = Record<string, CaseReducerDefinition<State, PayloadAction<any>> | CaseReducerWithPrepareDefinition<State, PayloadAction<any, string, any, any>> | AsyncThunkSliceReducerDefinition<State, any, any, any>> | Record<string, CaseReducer<State, PayloadAction<any>> | CaseReducerWithPrepare<State, PayloadAction<any, string, any, any>>>; | ||
export type SliceCaseReducers<State> = Record<string, ReducerDefinition> | Record<string, CaseReducer<State, PayloadAction<any>> | CaseReducerWithPrepare<State, PayloadAction<any, string, any, any>>>; | ||
/** | ||
@@ -247,0 +247,0 @@ * The type describing a slice's `selectors` option. |
import type { IdSelector, Comparer, EntityStateAdapter, EntityId } from './models'; | ||
export declare function createSortedStateAdapter<T, Id extends EntityId>(selectId: IdSelector<T, Id>, sort: Comparer<T>): EntityStateAdapter<T, Id>; | ||
export declare function findInsertIndex<T>(sortedItems: T[], item: T, comparisonFunction: Comparer<T>): number; | ||
export declare function insert<T>(sortedItems: T[], item: T, comparisonFunction: Comparer<T>): T[]; | ||
export declare function createSortedStateAdapter<T, Id extends EntityId>(selectId: IdSelector<T, Id>, comparer: Comparer<T>): EntityStateAdapter<T, Id>; |
import type { IdSelector, Update, EntityId, DraftableEntityState } from './models'; | ||
export declare function selectIdValue<T, Id extends EntityId>(entity: T, selectId: IdSelector<T, Id>): Id; | ||
export declare function ensureEntitiesArray<T, Id extends EntityId>(entities: readonly T[] | Record<Id, T>): readonly T[]; | ||
export declare function splitAddedUpdatedEntities<T, Id extends EntityId>(newEntities: readonly T[] | Record<Id, T>, selectId: IdSelector<T, Id>, state: DraftableEntityState<T, Id>): [T[], Update<T, Id>[]]; | ||
export declare function getCurrent<T>(value: T): T; | ||
export declare function splitAddedUpdatedEntities<T, Id extends EntityId>(newEntities: readonly T[] | Record<Id, T>, selectId: IdSelector<T, Id>, state: DraftableEntityState<T, Id>): [T[], Update<T, Id>[], Id[]]; |
@@ -28,3 +28,3 @@ export * from 'redux'; | ||
export { createAsyncThunk, unwrapResult, miniSerializeError, } from './createAsyncThunk'; | ||
export type { AsyncThunk, AsyncThunkOptions, AsyncThunkAction, AsyncThunkPayloadCreatorReturnValue, AsyncThunkPayloadCreator, SerializedError, } from './createAsyncThunk'; | ||
export type { AsyncThunk, AsyncThunkOptions, AsyncThunkAction, AsyncThunkPayloadCreatorReturnValue, AsyncThunkPayloadCreator, GetThunkAPI, SerializedError, } from './createAsyncThunk'; | ||
export { isAllOf, isAnyOf, isPending, isRejected, isFulfilled, isAsyncThunkAction, isRejectedWithValue, } from './matchers'; | ||
@@ -31,0 +31,0 @@ export type { ActionMatchingAllOf, ActionMatchingAnyOf, } from './matchers'; |
import type { ActionFromMatcher, Matcher, UnionToIntersection } from './tsHelpers'; | ||
import type { AsyncThunk, AsyncThunkFulfilledActionCreator, AsyncThunkPendingActionCreator, AsyncThunkRejectedActionCreator } from './createAsyncThunk'; | ||
/** @public */ | ||
export type ActionMatchingAnyOf<Matchers extends [...Matcher<any>[]]> = ActionFromMatcher<Matchers[number]>; | ||
export type ActionMatchingAnyOf<Matchers extends Matcher<any>[]> = ActionFromMatcher<Matchers[number]>; | ||
/** @public */ | ||
export type ActionMatchingAllOf<Matchers extends [...Matcher<any>[]]> = UnionToIntersection<ActionMatchingAnyOf<Matchers>>; | ||
export type ActionMatchingAllOf<Matchers extends Matcher<any>[]> = UnionToIntersection<ActionMatchingAnyOf<Matchers>>; | ||
/** | ||
@@ -16,3 +16,3 @@ * A higher-order function that returns a function that may be used to check | ||
*/ | ||
export declare function isAnyOf<Matchers extends [...Matcher<any>[]]>(...matchers: Matchers): (action: any) => action is ActionFromMatcher<Matchers[number]>; | ||
export declare function isAnyOf<Matchers extends Matcher<any>[]>(...matchers: Matchers): (action: any) => action is ActionFromMatcher<Matchers[number]>; | ||
/** | ||
@@ -27,3 +27,3 @@ * A higher-order function that returns a function that may be used to check | ||
*/ | ||
export declare function isAllOf<Matchers extends [...Matcher<any>[]]>(...matchers: Matchers): (action: any) => action is UnionToIntersection<ActionFromMatcher<Matchers[number]>>; | ||
export declare function isAllOf<Matchers extends Matcher<any>[]>(...matchers: Matchers): (action: any) => action is UnionToIntersection<ActionFromMatcher<Matchers[number]>>; | ||
/** | ||
@@ -30,0 +30,0 @@ * @param action A redux action |
@@ -51,3 +51,5 @@ import type { EndpointDefinitions, QueryDefinition, MutationDefinition, QueryArgFrom, ResultTypeFrom } from '../endpointDefinitions'; | ||
data: ResultTypeFrom<D>; | ||
error?: undefined; | ||
} | { | ||
data?: undefined; | ||
error: Exclude<BaseQueryError<D extends MutationDefinition<any, infer BaseQuery, any, any> ? BaseQuery : never>, undefined> | SerializedError; | ||
@@ -54,0 +56,0 @@ }> & { |
@@ -56,4 +56,4 @@ import type { createSelector as _createSelector } from './rtkImports'; | ||
}>; | ||
selectCachedArgsForQuery: <QueryName extends QueryKeys<Definitions>>(state: _RootState<Definitions, string, string>, queryName: QueryName) => QueryArgFrom<Definitions[QueryName]>[]; | ||
selectCachedArgsForQuery: <QueryName extends QueryKeys<Definitions>>(state: _RootState<Definitions, string, string>, queryName: QueryName) => Array<QueryArgFrom<Definitions[QueryName]>>; | ||
}; | ||
export {}; |
@@ -10,3 +10,3 @@ import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs'; | ||
import type { Patch } from 'immer'; | ||
import type { ThunkAction, AsyncThunk } from '@reduxjs/toolkit'; | ||
import type { ThunkAction, ThunkDispatch, AsyncThunk } from '@reduxjs/toolkit'; | ||
import type { PrefetchOptions } from './module'; | ||
@@ -111,3 +111,3 @@ import type { UnwrapPromise } from '../tsHelpers'; | ||
extra?: unknown; | ||
dispatch?: import("redux").Dispatch<UnknownAction> | undefined; | ||
dispatch?: ThunkDispatch<unknown, unknown, UnknownAction> | undefined; | ||
rejectValue?: unknown; | ||
@@ -132,3 +132,3 @@ serializedErrorType?: unknown; | ||
extra?: unknown; | ||
dispatch?: import("redux").Dispatch<UnknownAction> | undefined; | ||
dispatch?: ThunkDispatch<unknown, unknown, UnknownAction> | undefined; | ||
rejectValue?: unknown; | ||
@@ -135,0 +135,0 @@ serializedErrorType?: unknown; |
@@ -201,3 +201,3 @@ import type { Api, Module, ModuleName } from './apiTypes'; | ||
* ```ts | ||
* const MyContext = React.createContext<ReactReduxContextValue>(null as any); | ||
* const MyContext = React.createContext<ReactReduxContextValue | null>(null); | ||
* const customCreateApi = buildCreateApi( | ||
@@ -204,0 +204,0 @@ * coreModule(), |
import type { Context } from 'react'; | ||
import React from 'react'; | ||
import type { ReactReduxContextValue } from 'react-redux'; | ||
@@ -34,2 +35,2 @@ import { setupListeners } from '@reduxjs/toolkit/query'; | ||
context?: Context<ReactReduxContextValue | null>; | ||
}): JSX.Element; | ||
}): React.JSX.Element; |
@@ -77,3 +77,3 @@ import type { BaseQueryFn, EndpointDefinitions, Module, MutationDefinition, QueryArgFrom, QueryDefinition } from '@reduxjs/toolkit/query'; | ||
* ```ts | ||
* const MyContext = React.createContext<ReactReduxContextValue>(null as any); | ||
* const MyContext = React.createContext<ReactReduxContextValue | null>(null); | ||
* const customCreateApi = buildCreateApi( | ||
@@ -80,0 +80,0 @@ * coreModule(), |
@@ -78,6 +78,12 @@ var __defProp = Object.defineProperty; | ||
} else { | ||
const stringified = JSON.stringify(queryArgs, (key, value) => isPlainObject(value) ? Object.keys(value).sort().reduce((acc, key2) => { | ||
acc[key2] = value[key2]; | ||
return acc; | ||
}, {}) : value); | ||
const stringified = JSON.stringify(queryArgs, (key, value) => { | ||
value = typeof value === "bigint" ? { | ||
$bigint: value.toString() | ||
} : value; | ||
value = isPlainObject(value) ? Object.keys(value).sort().reduce((acc, key2) => { | ||
acc[key2] = value[key2]; | ||
return acc; | ||
}, {}) : value; | ||
return value; | ||
}); | ||
if (isPlainObject(queryArgs)) { | ||
@@ -183,3 +189,3 @@ cache == null ? void 0 : cache.set(queryArgs, stringified); | ||
const isFetching = currentState.isLoading; | ||
const isLoading = !hasData && isFetching; | ||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching; | ||
const isSuccess = currentState.isSuccess || isFetching && hasData; | ||
@@ -212,3 +218,3 @@ return __spreadProps(__spreadValues({}, currentState), { | ||
const dispatch = useDispatch(); | ||
const subscriptionSelectorsRef = useRef3(); | ||
const subscriptionSelectorsRef = useRef3(void 0); | ||
if (!subscriptionSelectorsRef.current) { | ||
@@ -242,3 +248,3 @@ const returnedValue = dispatch(api.internalActions.internal_getRTKQSubscriptions()); | ||
const lastRenderHadSubscription = useRef3(false); | ||
const promiseRef = useRef3(); | ||
const promiseRef = useRef3(void 0); | ||
let { | ||
@@ -314,3 +320,3 @@ queryCacheKey, | ||
const [arg, setArg] = useState(UNINITIALIZED_VALUE); | ||
const promiseRef = useRef3(); | ||
const promiseRef = useRef3(void 0); | ||
const stableSubscriptionOptions = useShallowStableValue({ | ||
@@ -367,3 +373,3 @@ refetchOnReconnect, | ||
const stableArg = useStableQueryArgs(skip ? skipToken : arg, serializeQueryArgs, context.endpointDefinitions[name], name); | ||
const lastValue = useRef3(); | ||
const lastValue = useRef3(void 0); | ||
const selectDefaultResult = useMemo2(() => createSelector2([select(stableArg), (_, lastResult) => lastResult, (_) => stableArg], queryStatePreSelector, { | ||
@@ -370,0 +376,0 @@ memoizeOptions: { |
@@ -1,4 +0,3 @@ | ||
import type { BaseQueryApi, BaseQueryArg, BaseQueryEnhancer, BaseQueryExtraOptions, BaseQueryFn } from './baseQueryTypes'; | ||
import type { FetchBaseQueryError } from './fetchBaseQuery'; | ||
type RetryConditionFunction = (error: FetchBaseQueryError, args: BaseQueryArg<BaseQueryFn>, extraArgs: { | ||
import type { BaseQueryApi, BaseQueryArg, BaseQueryEnhancer, BaseQueryError, BaseQueryExtraOptions, BaseQueryFn } from './baseQueryTypes'; | ||
type RetryConditionFunction = (error: BaseQueryError<BaseQueryFn>, args: BaseQueryArg<BaseQueryFn>, extraArgs: { | ||
attempt: number; | ||
@@ -5,0 +4,0 @@ baseQueryApi: BaseQueryApi; |
@@ -0,0 +0,0 @@ // inlined from https://github.com/EskiMojo14/uncheckedindexed |
{ | ||
"name": "@reduxjs/toolkit", | ||
"version": "2.2.3", | ||
"version": "2.2.4", | ||
"description": "The official, opinionated, batteries-included toolset for efficient Redux development", | ||
@@ -93,3 +93,3 @@ "author": "Mark Erikson <mark@isquaredsoftware.com>", | ||
"tsx": "^3.12.2", | ||
"typescript": "^5.3.3", | ||
"typescript": "^5.4.5", | ||
"vite-tsconfig-paths": "^4.3.1", | ||
@@ -123,3 +123,3 @@ "vitest": "^1.1.3", | ||
"redux-thunk": "^3.1.0", | ||
"reselect": "^5.0.1" | ||
"reselect": "^5.1.0" | ||
}, | ||
@@ -126,0 +126,0 @@ "peerDependencies": { |
@@ -0,0 +0,0 @@ { |
@@ -0,0 +0,0 @@ { |
@@ -0,0 +0,0 @@ { |
@@ -0,0 +0,0 @@ # Redux Toolkit |
@@ -0,0 +0,0 @@ import type { Middleware } from 'redux' |
@@ -0,0 +0,0 @@ import type { UnknownAction, Reducer, StateFromReducersMapObject } from 'redux' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import { isAction } from 'redux' |
@@ -119,3 +119,3 @@ import type { Dispatch, UnknownAction } from 'redux' | ||
state?: unknown | ||
dispatch?: Dispatch | ||
dispatch?: ThunkDispatch<unknown, unknown, UnknownAction> | ||
extra?: unknown | ||
@@ -244,3 +244,3 @@ rejectValue?: unknown | ||
> = ( | ||
dispatch: GetDispatch<ThunkApiConfig>, | ||
dispatch: NonNullable<GetDispatch<ThunkApiConfig>>, | ||
getState: () => GetState<ThunkApiConfig>, | ||
@@ -582,3 +582,3 @@ extra: GetExtra<ThunkApiConfig>, | ||
arg: ThunkArg, | ||
): AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig> { | ||
): AsyncThunkAction<Returned, ThunkArg, Required<ThunkApiConfig>> { | ||
return (dispatch, getState, extra) => { | ||
@@ -585,0 +585,0 @@ const requestId = options?.idGenerator |
@@ -0,0 +0,0 @@ import { current, isDraft } from 'immer' |
@@ -0,0 +0,0 @@ import type { Draft } from 'immer' |
@@ -430,13 +430,5 @@ import type { Action, UnknownAction, Reducer } from 'redux' | ||
export type SliceCaseReducers<State> = | ||
| Record<string, ReducerDefinition> | ||
| Record< | ||
string, | ||
| CaseReducerDefinition<State, PayloadAction<any>> | ||
| CaseReducerWithPrepareDefinition< | ||
State, | ||
PayloadAction<any, string, any, any> | ||
> | ||
| AsyncThunkSliceReducerDefinition<State, any, any, any> | ||
> | ||
| Record< | ||
string, | ||
| CaseReducer<State, PayloadAction<any>> | ||
@@ -696,3 +688,3 @@ | CaseReducerWithPrepare<State, PayloadAction<any, string, any, any>> | ||
reducerDetails, | ||
reducerDefinition, | ||
reducerDefinition as any, | ||
contextMethods, | ||
@@ -699,0 +691,0 @@ ) |
@@ -0,0 +0,0 @@ import type { Action, ActionCreator, StoreEnhancer } from 'redux' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import type { Action, Middleware, UnknownAction } from 'redux' |
@@ -0,0 +0,0 @@ import type { Middleware } from 'redux' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import type { EntityAdapter, EntityId, EntityAdapterOptions } from './models' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ export { createEntityAdapter } from './create_adapter' |
@@ -0,1 +1,2 @@ | ||
import { current, isDraft } from 'immer' | ||
import type { | ||
@@ -15,7 +16,42 @@ IdSelector, | ||
splitAddedUpdatedEntities, | ||
getCurrent, | ||
} from './utils' | ||
// Borrowed from Replay | ||
export function findInsertIndex<T>( | ||
sortedItems: T[], | ||
item: T, | ||
comparisonFunction: Comparer<T>, | ||
): number { | ||
let lowIndex = 0 | ||
let highIndex = sortedItems.length | ||
while (lowIndex < highIndex) { | ||
let middleIndex = (lowIndex + highIndex) >>> 1 | ||
const currentItem = sortedItems[middleIndex] | ||
const res = comparisonFunction(item, currentItem) | ||
if (res >= 0) { | ||
lowIndex = middleIndex + 1 | ||
} else { | ||
highIndex = middleIndex | ||
} | ||
} | ||
return lowIndex | ||
} | ||
export function insert<T>( | ||
sortedItems: T[], | ||
item: T, | ||
comparisonFunction: Comparer<T>, | ||
): T[] { | ||
const insertAtIndex = findInsertIndex(sortedItems, item, comparisonFunction) | ||
sortedItems.splice(insertAtIndex, 0, item) | ||
return sortedItems | ||
} | ||
export function createSortedStateAdapter<T, Id extends EntityId>( | ||
selectId: IdSelector<T, Id>, | ||
sort: Comparer<T>, | ||
comparer: Comparer<T>, | ||
): EntityStateAdapter<T, Id> { | ||
@@ -34,11 +70,16 @@ type R = DraftableEntityState<T, Id> | ||
state: R, | ||
existingIds?: Id[], | ||
): void { | ||
newEntities = ensureEntitiesArray(newEntities) | ||
const existingKeys = new Set<Id>( | ||
existingIds ?? (current(state.ids) as Id[]), | ||
) | ||
const models = newEntities.filter( | ||
(model) => !(selectIdValue(model, selectId) in state.entities), | ||
(model) => !existingKeys.has(selectIdValue(model, selectId)), | ||
) | ||
if (models.length !== 0) { | ||
merge(models, state) | ||
mergeFunction(state, models) | ||
} | ||
@@ -57,3 +98,6 @@ } | ||
if (newEntities.length !== 0) { | ||
merge(newEntities, state) | ||
for (const item of newEntities) { | ||
delete (state.entities as Record<Id, T>)[selectId(item)] | ||
} | ||
mergeFunction(state, newEntities) | ||
} | ||
@@ -70,3 +114,3 @@ } | ||
addManyMutably(newEntities, state) | ||
addManyMutably(newEntities, state, []) | ||
} | ||
@@ -83,2 +127,3 @@ | ||
let appliedUpdates = false | ||
let replacedIds = false | ||
@@ -95,4 +140,10 @@ for (let update of updates) { | ||
const newId = selectId(entity) | ||
if (update.id !== newId) { | ||
// We do support the case where updates can change an item's ID. | ||
// This makes things trickier - go ahead and swap the IDs in state now. | ||
replacedIds = true | ||
delete (state.entities as Record<Id, T>)[update.id] | ||
const oldIndex = (state.ids as Id[]).indexOf(update.id) | ||
state.ids[oldIndex] = newId | ||
;(state.entities as Record<Id, T>)[newId] = entity | ||
@@ -103,3 +154,3 @@ } | ||
if (appliedUpdates) { | ||
resortEntities(state) | ||
mergeFunction(state, [], appliedUpdates, replacedIds) | ||
} | ||
@@ -116,3 +167,3 @@ } | ||
): void { | ||
const [added, updated] = splitAddedUpdatedEntities<T, Id>( | ||
const [added, updated, existingIdsArray] = splitAddedUpdatedEntities<T, Id>( | ||
newEntities, | ||
@@ -123,4 +174,8 @@ selectId, | ||
updateManyMutably(updated, state) | ||
addManyMutably(added, state) | ||
if (updated.length) { | ||
updateManyMutably(updated, state) | ||
} | ||
if (added.length) { | ||
addManyMutably(added, state, existingIdsArray) | ||
} | ||
} | ||
@@ -142,19 +197,55 @@ | ||
function merge(models: readonly T[], state: R): void { | ||
type MergeFunction = ( | ||
state: R, | ||
addedItems: readonly T[], | ||
appliedUpdates?: boolean, | ||
replacedIds?: boolean, | ||
) => void | ||
const mergeInsertion: MergeFunction = ( | ||
state, | ||
addedItems, | ||
appliedUpdates, | ||
replacedIds, | ||
) => { | ||
const currentEntities = getCurrent(state.entities) as Record<Id, T> | ||
const currentIds = getCurrent(state.ids) as Id[] | ||
const stateEntities = state.entities as Record<Id, T> | ||
let ids = currentIds | ||
if (replacedIds) { | ||
ids = Array.from(new Set(currentIds)) | ||
} | ||
let sortedEntities: T[] = [] | ||
for (const id of ids) { | ||
const entity = currentEntities[id] | ||
if (entity) { | ||
sortedEntities.push(entity) | ||
} | ||
} | ||
const wasPreviouslyEmpty = sortedEntities.length === 0 | ||
// Insert/overwrite all new/updated | ||
models.forEach((model) => { | ||
;(state.entities as Record<Id, T>)[selectId(model)] = model | ||
}) | ||
for (const item of addedItems) { | ||
stateEntities[selectId(item)] = item | ||
resortEntities(state) | ||
} | ||
if (!wasPreviouslyEmpty) { | ||
// Binary search insertion generally requires fewer comparisons | ||
insert(sortedEntities, item, comparer) | ||
} | ||
} | ||
function resortEntities(state: R) { | ||
const allEntities = Object.values(state.entities) as T[] | ||
allEntities.sort(sort) | ||
if (wasPreviouslyEmpty) { | ||
// All we have is the incoming values, sort them | ||
sortedEntities = addedItems.slice().sort(comparer) | ||
} else if (appliedUpdates) { | ||
// We should have a _mostly_-sorted array already | ||
sortedEntities.sort(comparer) | ||
} | ||
const newSortedIds = allEntities.map(selectId) | ||
const { ids } = state | ||
const newSortedIds = sortedEntities.map(selectId) | ||
if (!areArraysEqual(ids, newSortedIds)) { | ||
if (!areArraysEqual(currentIds, newSortedIds)) { | ||
state.ids = newSortedIds | ||
@@ -164,2 +255,4 @@ } | ||
const mergeFunction: MergeFunction = mergeInsertion | ||
return { | ||
@@ -166,0 +259,0 @@ removeOne, |
@@ -0,0 +0,0 @@ import { produce as createNextState, isDraft } from 'immer' |
@@ -0,0 +0,0 @@ import type { CreateSelectorFunction, Selector, createSelector } from 'reselect' |
@@ -0,0 +0,0 @@ import type { EntityAdapter } from '../index' |
@@ -0,0 +0,0 @@ export interface BookModel { |
import type { EntityAdapter, EntityState } from '../models' | ||
import { createEntityAdapter } from '../create_adapter' | ||
import { createAction, createSlice, configureStore } from '@reduxjs/toolkit' | ||
import { | ||
createAction, | ||
createSlice, | ||
configureStore, | ||
nanoid, | ||
} from '@reduxjs/toolkit' | ||
import type { BookModel } from './fixtures/book' | ||
@@ -235,7 +240,7 @@ import { | ||
it('Replaces an existing entity if you change the ID while updating', () => { | ||
const withAdded = adapter.setAll(state, [ | ||
{ id: 'a', title: 'First' }, | ||
{ id: 'b', title: 'Second' }, | ||
{ id: 'c', title: 'Third' }, | ||
]) | ||
const a = { id: 'a', title: 'First' } | ||
const b = { id: 'b', title: 'Second' } | ||
const c = { id: 'c', title: 'Third' } | ||
const d = { id: 'd', title: 'Fourth' } | ||
const withAdded = adapter.setAll(state, [a, b, c]) | ||
@@ -251,3 +256,3 @@ const withUpdated = adapter.updateOne(withAdded, { | ||
expect(ids.length).toBe(2) | ||
expect(ids).toEqual(['a', 'c']) | ||
expect(entities.a).toBeTruthy() | ||
@@ -360,5 +365,6 @@ expect(entities.b).not.toBeTruthy() | ||
[ | ||
{ id: 'C', order: 3, ts: 0 }, | ||
{ id: 'A', order: 1, ts: 0 }, | ||
{ id: 'F', order: 4, ts: 0 }, | ||
{ id: 'B', order: 2, ts: 0 }, | ||
{ id: 'C', order: 3, ts: 0 }, | ||
{ id: 'D', order: 3, ts: 0 }, | ||
@@ -369,2 +375,4 @@ { id: 'E', order: 3, ts: 0 }, | ||
expect(withInitialItems.ids).toEqual(['A', 'B', 'C', 'D', 'E', 'F']) | ||
const updated = sortedItemsAdapter.updateOne(withInitialItems, { | ||
@@ -375,3 +383,10 @@ id: 'C', | ||
expect(updated.ids).toEqual(['A', 'B', 'C', 'D', 'E']) | ||
expect(updated.ids).toEqual(['A', 'B', 'C', 'D', 'E', 'F']) | ||
const updated2 = sortedItemsAdapter.updateOne(withInitialItems, { | ||
id: 'D', | ||
changes: { ts: 6 }, | ||
}) | ||
expect(updated2.ids).toEqual(['A', 'B', 'C', 'D', 'E', 'F']) | ||
}) | ||
@@ -592,2 +607,186 @@ | ||
it('should minimize the amount of sorting work needed', () => { | ||
const INITIAL_ITEMS = 10_000 | ||
const ADDED_ITEMS = 1_000 | ||
type Entity = { id: string; name: string; position: number } | ||
let numSorts = 0 | ||
const adaptor = createEntityAdapter({ | ||
selectId: (entity: Entity) => entity.id, | ||
sortComparer: (a, b) => { | ||
numSorts++ | ||
if (a.position < b.position) return -1 | ||
else if (a.position > b.position) return 1 | ||
return 0 | ||
}, | ||
}) | ||
function generateItems(count: number) { | ||
const items: readonly Entity[] = new Array(count) | ||
.fill(undefined) | ||
.map((x, i) => ({ | ||
name: `${i}`, | ||
position: Math.random(), | ||
id: nanoid(), | ||
})) | ||
return items | ||
} | ||
const entitySlice = createSlice({ | ||
name: 'entity', | ||
initialState: adaptor.getInitialState(), | ||
reducers: { | ||
updateOne: adaptor.updateOne, | ||
upsertOne: adaptor.upsertOne, | ||
upsertMany: adaptor.upsertMany, | ||
addMany: adaptor.addMany, | ||
}, | ||
}) | ||
const store = configureStore({ | ||
reducer: { | ||
entity: entitySlice.reducer, | ||
}, | ||
middleware: (getDefaultMiddleware) => { | ||
return getDefaultMiddleware({ | ||
serializableCheck: false, | ||
immutableCheck: false, | ||
}) | ||
}, | ||
}) | ||
numSorts = 0 | ||
const logComparisons = false | ||
function measureComparisons(name: string, cb: () => void) { | ||
numSorts = 0 | ||
const start = new Date().getTime() | ||
cb() | ||
const end = new Date().getTime() | ||
const duration = end - start | ||
if (logComparisons) { | ||
console.log( | ||
`${name}: sortComparer called ${numSorts.toLocaleString()} times in ${duration.toLocaleString()}ms`, | ||
) | ||
} | ||
} | ||
const initialItems = generateItems(INITIAL_ITEMS) | ||
measureComparisons('Original Setup', () => { | ||
store.dispatch(entitySlice.actions.upsertMany(initialItems)) | ||
}) | ||
expect(numSorts).toBeLessThan(INITIAL_ITEMS * 20) | ||
measureComparisons('Insert One (random)', () => { | ||
store.dispatch( | ||
entitySlice.actions.upsertOne({ | ||
id: nanoid(), | ||
position: Math.random(), | ||
name: 'test', | ||
}), | ||
) | ||
}) | ||
expect(numSorts).toBeLessThan(50) | ||
measureComparisons('Insert One (middle)', () => { | ||
store.dispatch( | ||
entitySlice.actions.upsertOne({ | ||
id: nanoid(), | ||
position: 0.5, | ||
name: 'test', | ||
}), | ||
) | ||
}) | ||
expect(numSorts).toBeLessThan(50) | ||
measureComparisons('Insert One (end)', () => { | ||
store.dispatch( | ||
entitySlice.actions.upsertOne({ | ||
id: nanoid(), | ||
position: 0.9998, | ||
name: 'test', | ||
}), | ||
) | ||
}) | ||
expect(numSorts).toBeLessThan(50) | ||
const addedItems = generateItems(ADDED_ITEMS) | ||
measureComparisons('Add Many', () => { | ||
store.dispatch(entitySlice.actions.addMany(addedItems)) | ||
}) | ||
expect(numSorts).toBeLessThan(ADDED_ITEMS * 20) | ||
// These numbers will vary because of the randomness, but generally | ||
// with 10K items the old code had 200K+ sort calls, while the new code | ||
// is around 13K sort calls. | ||
expect(numSorts).toBeLessThan(20_000) | ||
const { ids } = store.getState().entity | ||
const middleItemId = ids[(ids.length / 2) | 0] | ||
measureComparisons('Update One (end)', () => { | ||
store.dispatch( | ||
// Move this middle item near the end | ||
entitySlice.actions.updateOne({ | ||
id: middleItemId, | ||
changes: { | ||
position: 0.99999, | ||
}, | ||
}), | ||
) | ||
}) | ||
const SORTING_COUNT_BUFFER = 100 | ||
expect(numSorts).toBeLessThan( | ||
INITIAL_ITEMS + ADDED_ITEMS + SORTING_COUNT_BUFFER, | ||
) | ||
measureComparisons('Update One (middle)', () => { | ||
store.dispatch( | ||
// Move this middle item near the end | ||
entitySlice.actions.updateOne({ | ||
id: middleItemId, | ||
changes: { | ||
position: 0.42, | ||
}, | ||
}), | ||
) | ||
}) | ||
expect(numSorts).toBeLessThan( | ||
INITIAL_ITEMS + ADDED_ITEMS + SORTING_COUNT_BUFFER, | ||
) | ||
measureComparisons('Update One (replace)', () => { | ||
store.dispatch( | ||
// Move this middle item near the end | ||
entitySlice.actions.updateOne({ | ||
id: middleItemId, | ||
changes: { | ||
id: nanoid(), | ||
position: 0.98, | ||
}, | ||
}), | ||
) | ||
}) | ||
expect(numSorts).toBeLessThan( | ||
INITIAL_ITEMS + ADDED_ITEMS + SORTING_COUNT_BUFFER, | ||
) | ||
// The old code was around 120K, the new code is around 10K. | ||
//expect(numSorts).toBeLessThan(25_000) | ||
}) | ||
describe('can be used mutably when wrapped in createNextState', () => { | ||
@@ -594,0 +793,0 @@ test('removeAll', () => { |
@@ -0,0 +0,0 @@ import type { EntityAdapter } from '../index' |
@@ -0,0 +0,0 @@ import { createDraftSafeSelectorCreator } from '../../createDraftSafeSelector' |
@@ -0,0 +0,0 @@ import type { EntityAdapter, EntityState } from '../models' |
@@ -0,0 +0,0 @@ import { vi } from 'vitest' |
@@ -0,0 +0,0 @@ import type { Draft } from 'immer' |
@@ -0,1 +1,2 @@ | ||
import { current, isDraft } from 'immer' | ||
import type { | ||
@@ -38,2 +39,6 @@ IdSelector, | ||
export function getCurrent<T>(value: T): T { | ||
return isDraft(value) ? current(value) : value | ||
} | ||
export function splitAddedUpdatedEntities<T, Id extends EntityId>( | ||
@@ -43,5 +48,8 @@ newEntities: readonly T[] | Record<Id, T>, | ||
state: DraftableEntityState<T, Id>, | ||
): [T[], Update<T, Id>[]] { | ||
): [T[], Update<T, Id>[], Id[]] { | ||
newEntities = ensureEntitiesArray(newEntities) | ||
const existingIdsArray = current(state.ids) as Id[] | ||
const existingIds = new Set<Id>(existingIdsArray) | ||
const added: T[] = [] | ||
@@ -52,3 +60,3 @@ const updated: Update<T, Id>[] = [] | ||
const id = selectIdValue(entity, selectId) | ||
if (id in state.entities) { | ||
if (existingIds.has(id)) { | ||
updated.push({ id, changes: entity }) | ||
@@ -59,3 +67,3 @@ } else { | ||
} | ||
return [added, updated] | ||
return [added, updated, existingIdsArray] | ||
} |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ import type { StoreEnhancer } from 'redux' |
@@ -0,0 +0,0 @@ import type { Middleware, UnknownAction } from 'redux' |
@@ -0,0 +0,0 @@ import type { Middleware } from 'redux' |
@@ -133,2 +133,3 @@ // This must remain here so that the `mangleErrors.cjs` build script | ||
AsyncThunkPayloadCreator, | ||
GetThunkAPI, | ||
SerializedError, | ||
@@ -135,0 +136,0 @@ } from './createAsyncThunk' |
@@ -0,0 +0,0 @@ import type { SerializedError } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { Action, Dispatch, MiddlewareAPI, UnknownAction } from 'redux' |
@@ -0,0 +0,0 @@ import { TaskAbortError } from './exceptions' |
@@ -0,0 +0,0 @@ import { |
@@ -0,0 +0,0 @@ import type { EnhancedStore } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import { createListenerEntry } from '@internal/listenerMiddleware' |
@@ -0,0 +0,0 @@ import { |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import type { Action } from 'redux' |
@@ -0,0 +0,0 @@ import { |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import type { AbortSignalWithReason } from './types' |
@@ -0,0 +0,0 @@ import type { Action } from 'redux' |
@@ -15,7 +15,7 @@ import type { | ||
/** @public */ | ||
export type ActionMatchingAnyOf<Matchers extends [...Matcher<any>[]]> = | ||
export type ActionMatchingAnyOf<Matchers extends Matcher<any>[]> = | ||
ActionFromMatcher<Matchers[number]> | ||
/** @public */ | ||
export type ActionMatchingAllOf<Matchers extends [...Matcher<any>[]]> = | ||
export type ActionMatchingAllOf<Matchers extends Matcher<any>[]> = | ||
UnionToIntersection<ActionMatchingAnyOf<Matchers>> | ||
@@ -40,3 +40,3 @@ | ||
*/ | ||
export function isAnyOf<Matchers extends [...Matcher<any>[]]>( | ||
export function isAnyOf<Matchers extends Matcher<any>[]>( | ||
...matchers: Matchers | ||
@@ -58,3 +58,3 @@ ) { | ||
*/ | ||
export function isAllOf<Matchers extends [...Matcher<any>[]]>( | ||
export function isAllOf<Matchers extends Matcher<any>[]>( | ||
...matchers: Matchers | ||
@@ -142,14 +142,3 @@ ) { | ||
return ( | ||
action: any, | ||
): action is PendingActionFromAsyncThunk<AsyncThunks[number]> => { | ||
// note: this type will be correct because we have at least 1 asyncThunk | ||
const matchers: [Matcher<any>, ...Matcher<any>[]] = asyncThunks.map( | ||
(asyncThunk) => asyncThunk.pending, | ||
) as any | ||
const combinedMatcher = isAnyOf(...matchers) | ||
return combinedMatcher(action) | ||
} | ||
return isAnyOf(...asyncThunks.map((asyncThunk) => asyncThunk.pending)) | ||
} | ||
@@ -206,14 +195,3 @@ | ||
return ( | ||
action: any, | ||
): action is RejectedActionFromAsyncThunk<AsyncThunks[number]> => { | ||
// note: this type will be correct because we have at least 1 asyncThunk | ||
const matchers: [Matcher<any>, ...Matcher<any>[]] = asyncThunks.map( | ||
(asyncThunk) => asyncThunk.rejected, | ||
) as any | ||
const combinedMatcher = isAnyOf(...matchers) | ||
return combinedMatcher(action) | ||
} | ||
return isAnyOf(...asyncThunks.map((asyncThunk) => asyncThunk.rejected)) | ||
} | ||
@@ -272,7 +250,3 @@ | ||
if (asyncThunks.length === 0) { | ||
return (action: any) => { | ||
const combinedMatcher = isAllOf(isRejected(...asyncThunks), hasFlag) | ||
return combinedMatcher(action) | ||
} | ||
return isAllOf(isRejected(...asyncThunks), hasFlag) | ||
} | ||
@@ -284,9 +258,3 @@ | ||
return ( | ||
action: any, | ||
): action is RejectedActionFromAsyncThunk<AsyncThunks[number]> => { | ||
const combinedMatcher = isAllOf(isRejected(...asyncThunks), hasFlag) | ||
return combinedMatcher(action) | ||
} | ||
return isAllOf(isRejected(...asyncThunks), hasFlag) | ||
} | ||
@@ -343,14 +311,3 @@ | ||
return ( | ||
action: any, | ||
): action is FulfilledActionFromAsyncThunk<AsyncThunks[number]> => { | ||
// note: this type will be correct because we have at least 1 asyncThunk | ||
const matchers: [Matcher<any>, ...Matcher<any>[]] = asyncThunks.map( | ||
(asyncThunk) => asyncThunk.fulfilled, | ||
) as any | ||
const combinedMatcher = isAnyOf(...matchers) | ||
return combinedMatcher(action) | ||
} | ||
return isAnyOf(...asyncThunks.map((asyncThunk) => asyncThunk.fulfilled)) | ||
} | ||
@@ -415,20 +372,3 @@ | ||
return ( | ||
action: any, | ||
): action is ActionsFromAsyncThunk<AsyncThunks[number]> => { | ||
// note: this type will be correct because we have at least 1 asyncThunk | ||
const matchers: [Matcher<any>, ...Matcher<any>[]] = [] as any | ||
for (const asyncThunk of asyncThunks) { | ||
matchers.push( | ||
asyncThunk.pending, | ||
asyncThunk.rejected, | ||
asyncThunk.fulfilled, | ||
) | ||
} | ||
const combinedMatcher = isAnyOf(...matchers) | ||
return combinedMatcher(action) | ||
} | ||
return isAnyOf(...asyncThunks.flatMap(asyncThunk => [asyncThunk.pending, asyncThunk.rejected, asyncThunk.fulfilled])) | ||
} |
@@ -0,0 +0,0 @@ // Borrowed from https://github.com/ai/nanoid/blob/3.0.2/non-secure/index.js |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import type { ThunkDispatch } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { SerializedError } from '@reduxjs/toolkit' |
@@ -96,4 +96,8 @@ import type { | ||
> = SafePromise< | ||
| { data: ResultTypeFrom<D> } | ||
| { | ||
data: ResultTypeFrom<D> | ||
error?: undefined | ||
} | ||
| { | ||
data?: undefined | ||
error: | ||
@@ -100,0 +104,0 @@ | Exclude< |
@@ -0,0 +0,0 @@ import type { InternalHandlerBuilder, SubscriptionSelectors } from './types' |
@@ -0,0 +0,0 @@ import { isAsyncThunkAction, isFulfilled } from '../rtkImports' |
@@ -0,0 +0,0 @@ import type { InternalHandlerBuilder } from './types' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import { |
@@ -0,0 +0,0 @@ import type { QuerySubstateIdentifier, Subscribers } from '../apiState' |
@@ -0,0 +0,0 @@ import { isPending, isRejected, isFulfilled } from '../rtkImports' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import { QueryStatus } from '../apiState' |
@@ -0,0 +0,0 @@ import type { createSelector as _createSelector } from './rtkImports' |
@@ -0,0 +0,0 @@ import type { Action, PayloadAction, UnknownAction } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { InternalSerializeQueryArgs } from '../defaultSerializeQueryArgs' |
@@ -0,0 +0,0 @@ import { buildCreateApi, CreateApi } from '../createApi' |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ // This file exists to consolidate all of the imports from the `@reduxjs/toolkit` package. |
@@ -0,0 +0,0 @@ import type { |
@@ -236,3 +236,3 @@ import type { Api, ApiContext, Module, ModuleName } from './apiTypes' | ||
* ```ts | ||
* const MyContext = React.createContext<ReactReduxContextValue>(null as any); | ||
* const MyContext = React.createContext<ReactReduxContextValue | null>(null); | ||
* const customCreateApi = buildCreateApi( | ||
@@ -239,0 +239,0 @@ * coreModule(), |
@@ -20,4 +20,7 @@ import type { QueryCacheKey } from './core/apiState' | ||
} else { | ||
const stringified = JSON.stringify(queryArgs, (key, value) => | ||
isPlainObject(value) | ||
const stringified = JSON.stringify(queryArgs, (key, value) => { | ||
// Handle bigints | ||
value = typeof value === 'bigint' ? { $bigint: value.toString() } : value | ||
// Sort the object keys before stringifying, to prevent useQuery({ a: 1, b: 2 }) having a different cache key than useQuery({ b: 2, a: 1 }) | ||
value = isPlainObject(value) | ||
? Object.keys(value) | ||
@@ -29,4 +32,5 @@ .sort() | ||
}, {}) | ||
: value, | ||
) | ||
: value | ||
return value | ||
}) | ||
if (isPlainObject(queryArgs)) { | ||
@@ -37,3 +41,2 @@ cache?.set(queryArgs, stringified) | ||
} | ||
// Sort the object keys before stringifying, to prevent useQuery({ a: 1, b: 2 }) having a different cache key than useQuery({ b: 2, a: 1 }) | ||
return `${endpointName}(${serialized})` | ||
@@ -40,0 +43,0 @@ } |
@@ -0,0 +0,0 @@ import type { SerializeQueryArgs } from './defaultSerializeQueryArgs' |
@@ -0,0 +0,0 @@ import type { BaseQueryFn } from './baseQueryTypes' |
@@ -0,0 +0,0 @@ import { joinUrls } from './utils' |
@@ -0,0 +0,0 @@ export class HandledError { |
@@ -0,0 +0,0 @@ // This must remain here so that the `mangleErrors.cjs` build script |
@@ -693,3 +693,3 @@ import type { | ||
// isLoading = true only when loading while no data is present yet (initial load with no data in the cache) | ||
const isLoading = !hasData && isFetching | ||
const isLoading = (!lastResult || lastResult.isLoading || lastResult.isUninitialized) && !hasData && isFetching | ||
// isSuccess = true when data is present | ||
@@ -744,3 +744,11 @@ const isSuccess = currentState.isSuccess || (isFetching && hasData) | ||
const dispatch = useDispatch<ThunkDispatch<any, any, UnknownAction>>() | ||
const subscriptionSelectorsRef = useRef<SubscriptionSelectors>() | ||
// TODO: Change this to `useRef<SubscriptionSelectors>(undefined)` after upgrading to React 19. | ||
/** | ||
* @todo Change this to `useRef<SubscriptionSelectors>(undefined)` after upgrading to React 19. | ||
*/ | ||
const subscriptionSelectorsRef = useRef< | ||
SubscriptionSelectors | undefined | ||
>(undefined) | ||
if (!subscriptionSelectorsRef.current) { | ||
@@ -786,3 +794,9 @@ const returnedValue = dispatch( | ||
const promiseRef = useRef<QueryActionCreatorResult<any>>() | ||
// TODO: Change this to `useRef<QueryActionCreatorResult<any>>(undefined)` after upgrading to React 19. | ||
/** | ||
* @todo Change this to `useRef<QueryActionCreatorResult<any>>(undefined)` after upgrading to React 19. | ||
*/ | ||
const promiseRef = useRef<QueryActionCreatorResult<any> | undefined>( | ||
undefined, | ||
) | ||
@@ -892,4 +906,11 @@ let { queryCacheKey, requestId } = promiseRef.current || {} | ||
const [arg, setArg] = useState<any>(UNINITIALIZED_VALUE) | ||
const promiseRef = useRef<QueryActionCreatorResult<any> | undefined>() | ||
// TODO: Change this to `useRef<QueryActionCreatorResult<any>>(undefined)` after upgrading to React 19. | ||
/** | ||
* @todo Change this to `useRef<QueryActionCreatorResult<any>>(undefined)` after upgrading to React 19. | ||
*/ | ||
const promiseRef = useRef<QueryActionCreatorResult<any> | undefined>( | ||
undefined, | ||
) | ||
const stableSubscriptionOptions = useShallowStableValue({ | ||
@@ -973,3 +994,3 @@ refetchOnReconnect, | ||
const lastValue = useRef<any>() | ||
const lastValue = useRef<any>(undefined) | ||
@@ -976,0 +997,0 @@ const selectDefaultResult: Selector<ApiRootState, any, [any]> = useMemo( |
export const UNINITIALIZED_VALUE = Symbol() | ||
export type UninitializedValue = typeof UNINITIALIZED_VALUE |
@@ -0,0 +0,0 @@ // This must remain here so that the `mangleErrors.cjs` build script |
@@ -127,3 +127,3 @@ import type { | ||
* ```ts | ||
* const MyContext = React.createContext<ReactReduxContextValue>(null as any); | ||
* const MyContext = React.createContext<ReactReduxContextValue | null>(null); | ||
* const customCreateApi = buildCreateApi( | ||
@@ -130,0 +130,0 @@ * coreModule(), |
@@ -0,0 +0,0 @@ import type { UseMutation, UseLazyQuery, UseQuery } from './buildHooks' |
@@ -0,0 +0,0 @@ import { useEffect, useRef, useMemo } from 'react' |
@@ -0,0 +0,0 @@ import { useEffect, useRef } from 'react' |
@@ -5,2 +5,3 @@ import type { | ||
BaseQueryEnhancer, | ||
BaseQueryError, | ||
BaseQueryExtraOptions, | ||
@@ -35,3 +36,3 @@ BaseQueryFn, | ||
type RetryConditionFunction = ( | ||
error: FetchBaseQueryError, | ||
error: BaseQueryError<BaseQueryFn>, | ||
args: BaseQueryArg<BaseQueryFn>, | ||
@@ -38,0 +39,0 @@ extraArgs: { |
@@ -0,0 +0,0 @@ import { createApi, fetchBaseQuery, retry } from '@reduxjs/toolkit/query' |
@@ -0,0 +0,0 @@ import { createApi } from '@reduxjs/toolkit/query' |
@@ -0,0 +0,0 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' |
@@ -0,0 +0,0 @@ import { createSlice } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query' |
@@ -0,0 +0,0 @@ import type { FetchBaseQueryMeta } from '@reduxjs/toolkit/query' |
@@ -0,0 +0,0 @@ import { |
@@ -0,0 +0,0 @@ import { copyWithStructuralSharing } from '@reduxjs/toolkit/query' |
@@ -0,0 +0,0 @@ import { setupApiStore } from '@internal/tests/utils/helpers' |
@@ -0,0 +0,0 @@ import { server } from '@internal/query/tests/mocks/server' |
@@ -26,2 +26,12 @@ import { defaultSerializeQueryArgs } from '@internal/query/defaultSerializeQueryArgs' | ||
test('bigint arg has non-default serialization (intead of throwing)', () => { | ||
expect( | ||
defaultSerializeQueryArgs({ | ||
endpointDefinition, | ||
endpointName, | ||
queryArgs: BigInt(10), | ||
}), | ||
).toMatchInlineSnapshot(`"test({"$bigint":"10"})"`) | ||
}) | ||
test('simple object arg is sorted', () => { | ||
@@ -28,0 +38,0 @@ expect( |
@@ -0,0 +0,0 @@ import { headersToObject } from 'headers-polyfill' |
@@ -0,0 +0,0 @@ import { setupServer } from 'msw/node' |
@@ -0,0 +0,0 @@ import { createApi, QueryStatus } from '@reduxjs/toolkit/query' |
@@ -0,0 +0,0 @@ import type { RetryOptions } from '@internal/query/retry' |
@@ -1,2 +0,3 @@ | ||
import type { BaseQueryFn } from '@reduxjs/toolkit/query' | ||
import { vi } from 'vitest' | ||
import type { BaseQueryFn, FetchBaseQueryError } from '@reduxjs/toolkit/query' | ||
import { createApi, retry } from '@reduxjs/toolkit/query' | ||
@@ -425,3 +426,4 @@ import { setupApiStore } from '../../tests/utils/helpers' | ||
extraOptions: { | ||
retryCondition: (e) => e.data === 'hello retryCondition', | ||
retryCondition: (e) => | ||
(e as FetchBaseQueryError).data === 'hello retryCondition', | ||
}, | ||
@@ -428,0 +430,0 @@ }), |
@@ -0,0 +0,0 @@ import type { SerializedError } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import { vi } from 'vitest' |
@@ -0,0 +0,0 @@ export type Id<T> = { [K in keyof T]: T[K] } & {} |
export function capitalize(str: string) { | ||
return str.replace(str[0], str[0].toUpperCase()) | ||
} |
@@ -0,0 +0,0 @@ import { isPlainObject as _iPO } from '../core/rtkImports' |
@@ -0,0 +0,0 @@ // Fast method for counting an object's keys |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ export * from './isAbsoluteUrl' |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ /** |
export function isNotNullish<T>(v: T | null | undefined): v is T { | ||
return v != null | ||
} |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ export function isValidUrl(string: string) { |
@@ -0,0 +0,0 @@ import { isAbsoluteUrl } from './isAbsoluteUrl' |
@@ -0,0 +0,0 @@ // This must remain here so that the `mangleErrors.cjs` build script |
@@ -0,0 +0,0 @@ import type { Middleware } from 'redux' |
@@ -0,0 +0,0 @@ import type { ActionCreatorInvariantMiddlewareOptions } from '@internal/actionCreatorInvariantMiddleware' |
@@ -0,0 +0,0 @@ import { configureStore } from '../configureStore' |
@@ -0,0 +0,0 @@ import type { PayloadAction } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { Reducer, Slice, WithSlice } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { WithSlice } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import * as DevTools from '@internal/devtoolsExtension' |
@@ -0,0 +0,0 @@ import { createAction, isActionCreator } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import type { UnknownAction } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import { createDraftSafeSelector, createSelector } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import { createDraftSafeSelector } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { |
@@ -46,6 +46,9 @@ import type { ActionReducerMapBuilder, Reducer } from '@reduxjs/toolkit' | ||
createReducer<string>(0 as number, (builder) => { | ||
// @ts-expect-error | ||
builder | ||
.addCase('increment', incrementHandler) | ||
.addCase('decrement', decrementHandler) | ||
expectTypeOf(builder.addCase) | ||
.parameter(1) | ||
.not.toMatchTypeOf(incrementHandler) | ||
expectTypeOf(builder.addCase) | ||
.parameter(1) | ||
.not.toMatchTypeOf(decrementHandler) | ||
}) | ||
@@ -52,0 +55,0 @@ }) |
@@ -0,0 +0,0 @@ import { vi } from 'vitest' |
@@ -655,2 +655,34 @@ import type { | ||
), | ||
testInferVoid: create.asyncThunk(() => {}, { | ||
pending(state, action) { | ||
expectTypeOf(state).toEqualTypeOf<TestState>() | ||
expectTypeOf(action.meta.arg).toBeVoid() | ||
}, | ||
fulfilled(state, action) { | ||
expectTypeOf(state).toEqualTypeOf<TestState>() | ||
expectTypeOf(action.meta.arg).toBeVoid() | ||
expectTypeOf(action.payload).toBeVoid() | ||
}, | ||
rejected(state, action) { | ||
expectTypeOf(state).toEqualTypeOf<TestState>() | ||
expectTypeOf(action.meta.arg).toBeVoid() | ||
expectTypeOf(action.error).toEqualTypeOf<SerializedError>() | ||
}, | ||
settled(state, action) { | ||
expectTypeOf(state).toEqualTypeOf<TestState>() | ||
expectTypeOf(action.meta.arg).toBeVoid() | ||
if (isRejected(action)) { | ||
expectTypeOf(action.error).toEqualTypeOf<SerializedError>() | ||
} else { | ||
expectTypeOf(action.payload).toBeVoid() | ||
} | ||
}, | ||
}), | ||
testInfer: create.asyncThunk( | ||
@@ -860,2 +892,8 @@ function payloadCreator(arg: TestArg, api) { | ||
expectTypeOf(slice.actions.testInferVoid).toEqualTypeOf< | ||
AsyncThunk<void, void, {}> | ||
>() | ||
expectTypeOf(slice.actions.testInferVoid).toBeCallableWith() | ||
expectTypeOf(slice.actions.testInfer).toEqualTypeOf< | ||
@@ -862,0 +900,0 @@ AsyncThunk<TestReturned, TestArg, {}> |
@@ -681,3 +681,3 @@ import type { PayloadAction, WithSlice } from '@reduxjs/toolkit' | ||
thunkReducers: create.asyncThunk( | ||
function payloadCreator(arg, api) { | ||
function payloadCreator(arg: string, api) { | ||
return Promise.resolve('resolved payload') | ||
@@ -726,3 +726,3 @@ }, | ||
// payloadCreator isn't allowed to return never | ||
function payloadCreator(arg, api): any { | ||
function payloadCreator(arg: string, api): any { | ||
throw new Error('') | ||
@@ -770,3 +770,3 @@ }, | ||
thunkReducers: create.asyncThunk( | ||
function payloadCreator(arg, api) { | ||
function payloadCreator(arg: string, api) { | ||
return 'should not call this' | ||
@@ -839,3 +839,2 @@ }, | ||
'fakeRequestId', | ||
{}, | ||
), | ||
@@ -842,0 +841,0 @@ ), |
@@ -0,0 +0,0 @@ import type { StoreEnhancer } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import { buildGetDefaultMiddleware } from '@internal/getDefaultMiddleware' |
@@ -0,0 +0,0 @@ import { Tuple } from '@internal/utils' |
@@ -0,0 +0,0 @@ import type { |
@@ -0,0 +0,0 @@ import type { SerializedError } from '@internal/createAsyncThunk' |
@@ -0,0 +0,0 @@ import type { UnknownAction } from 'redux' |
@@ -0,0 +0,0 @@ import { vi } from 'vitest' |
@@ -0,0 +0,0 @@ import { |
@@ -0,0 +0,0 @@ import { Tuple } from '@reduxjs/toolkit' |
@@ -0,0 +0,0 @@ import type { Assertion, AsymmetricMatchersContaining } from 'vitest' |
@@ -0,0 +0,0 @@ import type { Middleware, StoreEnhancer } from 'redux' |
@@ -0,0 +0,0 @@ // inlined from https://github.com/EskiMojo14/uncheckedindexed |
@@ -0,0 +0,0 @@ import { produce as createNextState, isDraftable } from 'immer' |
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
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
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 too big to display
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
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 too big to display
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
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
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
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
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
5527607
64055
Updatedreselect@^5.1.0