Skip to content

Commit 8332c84

Browse files
committed
Update types with PreloadedState generic
1 parent 1551396 commit 8332c84

File tree

5 files changed

+176
-35
lines changed

5 files changed

+176
-35
lines changed

packages/toolkit/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@
113113
],
114114
"dependencies": {
115115
"immer": "^10.0.0-beta.4",
116-
"redux": "5.0.0-alpha.4",
116+
"redux": "5.0.0-alpha.5",
117117
"redux-thunk": "3.0.0-alpha.3",
118118
"reselect": "^4.1.7"
119119
},

packages/toolkit/src/configureStore.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import type {
77
StoreEnhancer,
88
Store,
99
Dispatch,
10-
PreloadedState,
11-
CombinedState,
1210
} from 'redux'
1311
import { createStore, compose, applyMiddleware, combineReducers } from 'redux'
1412
import type { DevToolsEnhancerOptions as DevToolsOptions } from './devtoolsExtension'
@@ -21,7 +19,6 @@ import type {
2119
} from './getDefaultMiddleware'
2220
import { curryGetDefaultMiddleware } from './getDefaultMiddleware'
2321
import type {
24-
NoInfer,
2522
ExtractDispatchExtensions,
2623
ExtractStoreExtensions,
2724
} from './tsHelpers'
@@ -46,13 +43,16 @@ export interface ConfigureStoreOptions<
4643
S = any,
4744
A extends Action = AnyAction,
4845
M extends Middlewares<S> = Middlewares<S>,
49-
E extends Enhancers = Enhancers
46+
E extends Enhancers = Enhancers,
47+
PreloadedState = S
5048
> {
5149
/**
5250
* A single reducer function that will be used as the root reducer, or an
5351
* object of slice reducers that will be passed to `combineReducers()`.
5452
*/
55-
reducer: Reducer<S, A> | ReducersMapObject<S, A>
53+
reducer:
54+
| Reducer<S, A, PreloadedState>
55+
| ReducersMapObject<S, A, PreloadedState>
5656

5757
/**
5858
* An array of Redux middleware to install. If not supplied, defaults to
@@ -87,7 +87,7 @@ export interface ConfigureStoreOptions<
8787
As we cannot distinguish between those two cases without adding another generic parameter,
8888
we just make the pragmatic assumption that the latter almost never happens.
8989
*/
90-
preloadedState?: PreloadedState<CombinedState<NoInfer<S>>>
90+
preloadedState?: PreloadedState
9191

9292
/**
9393
* The store enhancers to apply. See Redux's `createStore()`.
@@ -142,8 +142,11 @@ export function configureStore<
142142
S = any,
143143
A extends Action = AnyAction,
144144
M extends Middlewares<S> = [ThunkMiddlewareFor<S>],
145-
E extends Enhancers = [StoreEnhancer]
146-
>(options: ConfigureStoreOptions<S, A, M, E>): EnhancedStore<S, A, M, E> {
145+
E extends Enhancers = [StoreEnhancer],
146+
PreloadedState = S
147+
>(
148+
options: ConfigureStoreOptions<S, A, M, E, PreloadedState>
149+
): EnhancedStore<S, A, M, E> {
147150
const curriedGetDefaultMiddleware = curryGetDefaultMiddleware<S>()
148151

149152
const {
@@ -154,12 +157,16 @@ export function configureStore<
154157
enhancers = undefined,
155158
} = options || {}
156159

157-
let rootReducer: Reducer<S, A>
160+
let rootReducer: Reducer<S, A, PreloadedState>
158161

159162
if (typeof reducer === 'function') {
160163
rootReducer = reducer
161164
} else if (isPlainObject(reducer)) {
162-
rootReducer = combineReducers(reducer) as unknown as Reducer<S, A>
165+
rootReducer = combineReducers(reducer) as unknown as Reducer<
166+
S,
167+
A,
168+
PreloadedState
169+
>
163170
} else {
164171
throw new Error(
165172
'"reducer" is a required argument, and must be a function or an object of functions that can be passed to combineReducers'

packages/toolkit/src/query/core/buildSlice.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
prepareAutoBatched,
1111
} from '@reduxjs/toolkit'
1212
import type {
13-
CombinedState as CombinedQueryState,
1413
QuerySubstateIdentifier,
1514
QuerySubState,
1615
MutationSubstateIdentifier,
@@ -469,9 +468,7 @@ export function buildSlice({
469468
},
470469
})
471470

472-
const combinedReducer = combineReducers<
473-
CombinedQueryState<any, string, string>
474-
>({
471+
const combinedReducer = combineReducers({
475472
queries: querySlice.reducer,
476473
mutations: mutationSlice.reducer,
477474
provided: invalidationSlice.reducer,

packages/toolkit/src/tests/configureStore.typetest.ts

Lines changed: 152 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
Action,
99
StoreEnhancer,
1010
} from 'redux'
11-
import { applyMiddleware } from 'redux'
11+
import { applyMiddleware, combineReducers } from 'redux'
1212
import type { PayloadAction, ConfigureStoreOptions } from '@reduxjs/toolkit'
1313
import {
1414
configureStore,
@@ -130,8 +130,8 @@ const _anyMiddleware: any = () => () => () => {}
130130
})
131131

132132
configureStore({
133-
reducer: () => 0,
134133
// @ts-expect-error
134+
reducer: (_: number) => 0,
135135
preloadedState: 'non-matching state type',
136136
})
137137
}
@@ -197,25 +197,162 @@ const _anyMiddleware: any = () => () => () => {}
197197
}
198198

199199
/**
200-
* Test: configureStore() state type inference works when specifying both a
201-
* reducer object and a partial preloaded state.
200+
* Test: Preloaded state typings
202201
*/
203202
{
204203
let counterReducer1: Reducer<number> = () => 0
205204
let counterReducer2: Reducer<number> = () => 0
206205

207-
const store = configureStore({
208-
reducer: {
209-
counter1: counterReducer1,
210-
counter2: counterReducer2,
211-
},
212-
preloadedState: {
213-
counter1: 0,
214-
},
215-
})
206+
/**
207+
* Test: partial preloaded state
208+
*/
209+
{
210+
const store = configureStore({
211+
reducer: {
212+
counter1: counterReducer1,
213+
counter2: counterReducer2,
214+
},
215+
preloadedState: {
216+
counter1: 0,
217+
},
218+
})
219+
220+
const counter1: number = store.getState().counter1
221+
const counter2: number = store.getState().counter2
222+
}
223+
224+
/**
225+
* Test: empty preloaded state
226+
*/
227+
{
228+
const store = configureStore({
229+
reducer: {
230+
counter1: counterReducer1,
231+
counter2: counterReducer2,
232+
},
233+
preloadedState: {},
234+
})
235+
236+
const counter1: number = store.getState().counter1
237+
const counter2: number = store.getState().counter2
238+
}
239+
240+
/**
241+
* Test: excess properties in preloaded state
242+
*/
243+
{
244+
const store = configureStore({
245+
reducer: {
246+
// @ts-expect-error
247+
counter1: counterReducer1,
248+
counter2: counterReducer2,
249+
},
250+
preloadedState: {
251+
counter1: 0,
252+
counter3: 5,
253+
},
254+
})
255+
256+
const counter1: number = store.getState().counter1
257+
const counter2: number = store.getState().counter2
258+
}
259+
260+
/**
261+
* Test: mismatching properties in preloaded state
262+
*/
263+
{
264+
const store = configureStore({
265+
reducer: {
266+
// @ts-expect-error
267+
counter1: counterReducer1,
268+
counter2: counterReducer2,
269+
},
270+
preloadedState: {
271+
counter3: 5,
272+
},
273+
})
274+
275+
const counter1: number = store.getState().counter1
276+
const counter2: number = store.getState().counter2
277+
}
278+
279+
/**
280+
* Test: string preloaded state when expecting object
281+
*/
282+
{
283+
const store = configureStore({
284+
reducer: {
285+
// @ts-expect-error
286+
counter1: counterReducer1,
287+
counter2: counterReducer2,
288+
},
289+
preloadedState: 'test',
290+
})
291+
292+
const counter1: number = store.getState().counter1
293+
const counter2: number = store.getState().counter2
294+
}
216295

217-
const counter1: number = store.getState().counter1
218-
const counter2: number = store.getState().counter2
296+
/**
297+
* Test: nested combineReducers allows partial
298+
*/
299+
{
300+
const store = configureStore({
301+
reducer: {
302+
group1: combineReducers({
303+
counter1: counterReducer1,
304+
counter2: counterReducer2,
305+
}),
306+
group2: combineReducers({
307+
counter1: counterReducer1,
308+
counter2: counterReducer2,
309+
}),
310+
},
311+
preloadedState: {
312+
group1: {
313+
counter1: 5,
314+
},
315+
},
316+
})
317+
318+
const group1counter1: number = store.getState().group1.counter1
319+
const group1counter2: number = store.getState().group1.counter2
320+
const group2counter1: number = store.getState().group2.counter1
321+
const group2counter2: number = store.getState().group2.counter2
322+
}
323+
324+
/**
325+
* Test: non-nested combineReducers does not allow partial
326+
*/
327+
{
328+
interface GroupState {
329+
counter1: number
330+
counter2: number
331+
}
332+
333+
const initialState = { counter1: 0, counter2: 0 }
334+
335+
const group1Reducer: Reducer<GroupState> = (state = initialState) => state
336+
const group2Reducer: Reducer<GroupState> = (state = initialState) => state
337+
338+
const store = configureStore({
339+
reducer: {
340+
// @ts-expect-error
341+
group1: group1Reducer,
342+
group2: group2Reducer,
343+
},
344+
preloadedState: {
345+
group1: {
346+
counter1: 5,
347+
},
348+
},
349+
})
350+
351+
const group1counter1: number = store.getState().group1.counter1
352+
const group1counter2: number = store.getState().group1.counter2
353+
const group2counter1: number = store.getState().group2.counter1
354+
const group2counter2: number = store.getState().group2.counter2
355+
}
219356
}
220357

221358
/**

yarn.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6781,7 +6781,7 @@ __metadata:
67816781
node-fetch: ^2.6.1
67826782
prettier: ^2.2.1
67836783
query-string: ^7.0.1
6784-
redux: 5.0.0-alpha.4
6784+
redux: 5.0.0-alpha.5
67856785
redux-thunk: 3.0.0-alpha.3
67866786
reselect: ^4.1.7
67876787
rimraf: ^3.0.2
@@ -24576,10 +24576,10 @@ fsevents@^1.2.7:
2457624576
languageName: node
2457724577
linkType: hard
2457824578

24579-
"redux@npm:5.0.0-alpha.4":
24580-
version: 5.0.0-alpha.4
24581-
resolution: "redux@npm:5.0.0-alpha.4"
24582-
checksum: ebc98a74d84341df6db87222b6e54a658d68233924315ff67b4b2988ca0ea359e39632f7a43b65ec361ea7ba5714de4e34d76cb0b20089e785d11dc9e5a9e85e
24579+
"redux@npm:5.0.0-alpha.5":
24580+
version: 5.0.0-alpha.5
24581+
resolution: "redux@npm:5.0.0-alpha.5"
24582+
checksum: 4223be43f605c0d514d5d611a281ae703f905ed4c6014c81b55d1f59cdeac38e3c82fcee2671b102f6b681d95c2a6a9a0f598e044916378011fa0aa39dc644ad
2458324583
languageName: node
2458424584
linkType: hard
2458524585

0 commit comments

Comments
 (0)