Skip to content

Commit ac6aeb1

Browse files
authored
Merge pull request #3367 from EskiMojo14/redux-alpha5
2 parents 1551396 + 147429c commit ac6aeb1

File tree

13 files changed

+218
-67
lines changed

13 files changed

+218
-67
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: 10 additions & 19 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,14 @@ 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+
P = 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: Reducer<S, A, P> | ReducersMapObject<S, A, P>
5654

5755
/**
5856
* An array of Redux middleware to install. If not supplied, defaults to
@@ -78,16 +76,8 @@ export interface ConfigureStoreOptions<
7876
* function (either directly or indirectly by passing an object as `reducer`),
7977
* this must be an object with the same shape as the reducer map keys.
8078
*/
81-
/*
82-
Not 100% correct but the best approximation we can get:
83-
- if S is a `CombinedState` applying a second `CombinedState` on it does not change anything.
84-
- if it is not, there could be two cases:
85-
- `ReducersMapObject<S, A>` is being passed in. In this case, we will call `combineReducers` on it and `CombinedState<S>` is correct
86-
- `Reducer<S, A>` is being passed in. In this case, actually `CombinedState<S>` is wrong and `S` would be correct.
87-
As we cannot distinguish between those two cases without adding another generic parameter,
88-
we just make the pragmatic assumption that the latter almost never happens.
89-
*/
90-
preloadedState?: PreloadedState<CombinedState<NoInfer<S>>>
79+
// we infer here, and instead complain if the reducer doesn't match
80+
preloadedState?: P
9181

9282
/**
9383
* The store enhancers to apply. See Redux's `createStore()`.
@@ -142,8 +132,9 @@ export function configureStore<
142132
S = any,
143133
A extends Action = AnyAction,
144134
M extends Middlewares<S> = [ThunkMiddlewareFor<S>],
145-
E extends Enhancers = [StoreEnhancer]
146-
>(options: ConfigureStoreOptions<S, A, M, E>): EnhancedStore<S, A, M, E> {
135+
E extends Enhancers = [StoreEnhancer],
136+
P = S
137+
>(options: ConfigureStoreOptions<S, A, M, E, P>): EnhancedStore<S, A, M, E> {
147138
const curriedGetDefaultMiddleware = curryGetDefaultMiddleware<S>()
148139

149140
const {
@@ -154,12 +145,12 @@ export function configureStore<
154145
enhancers = undefined,
155146
} = options || {}
156147

157-
let rootReducer: Reducer<S, A>
148+
let rootReducer: Reducer<S, A, P>
158149

159150
if (typeof reducer === 'function') {
160151
rootReducer = reducer
161152
} else if (isPlainObject(reducer)) {
162-
rootReducer = combineReducers(reducer) as unknown as Reducer<S, A>
153+
rootReducer = combineReducers(reducer) as unknown as Reducer<S, A, P>
163154
} else {
164155
throw new Error(
165156
'"reducer" is a required argument, and must be a function or an object of functions that can be passed to combineReducers'

packages/toolkit/src/createAction.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,15 +286,19 @@ export function createAction(type: string, prepareAction?: Function): any {
286286
return actionCreator
287287
}
288288

289+
export function isAction(action: unknown): action is Action<unknown> {
290+
return isPlainObject(action) && 'type' in action
291+
}
292+
289293
export function isFSA(action: unknown): action is {
290294
type: string
291295
payload?: unknown
292296
error?: unknown
293297
meta?: unknown
294298
} {
295299
return (
296-
isPlainObject(action) &&
297-
typeof (action as any).type === 'string' &&
300+
isAction(action) &&
301+
typeof action.type === 'string' &&
298302
Object.keys(action).every(isValidKey)
299303
)
300304
}

packages/toolkit/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export {
3232
// js
3333
createAction,
3434
getType,
35+
isAction,
36+
isFSA as isFluxStandardAction,
3537
} from './createAction'
3638
export type {
3739
// types

packages/toolkit/src/listenerMiddleware/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Dispatch, AnyAction, MiddlewareAPI } from 'redux'
22
import type { ThunkDispatch } from 'redux-thunk'
3-
import { createAction } from '../createAction'
3+
import { createAction, isAction } from '../createAction'
44
import { nanoid } from '../nanoid'
55

66
import type {
@@ -426,6 +426,11 @@ export function createListenerMiddleware<
426426

427427
const middleware: ListenerMiddleware<S, D, ExtraArgument> =
428428
(api) => (next) => (action) => {
429+
if (!isAction(action)) {
430+
// this means that the listeners can't react to anything that doesn't look like an action (plain object with .type property)
431+
// but that matches the typing, so i think that's fine?
432+
return next(action)
433+
}
429434
if (addListener.match(action)) {
430435
return startListening(action.payload)
431436
}

packages/toolkit/src/listenerMiddleware/tests/fork.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ describe('fork', () => {
367367
},
368368
})
369369

370-
store.dispatch(increment)
370+
store.dispatch(increment())
371371

372372
expect(await deferredResult).toBe(listenerCompleted)
373373
})

packages/toolkit/src/query/core/buildMiddleware/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { AnyAction, Middleware, ThunkDispatch } from '@reduxjs/toolkit'
2-
import { createAction } from '@reduxjs/toolkit'
2+
import { isAction, createAction } from '@reduxjs/toolkit'
33

44
import type {
55
EndpointDefinitions,
@@ -80,6 +80,9 @@ export function buildMiddleware<
8080

8181
return (next) => {
8282
return (action) => {
83+
if (!isAction(action)) {
84+
return next(action)
85+
}
8386
if (!initialized) {
8487
initialized = true
8588
// dispatch before any other action

packages/toolkit/src/query/core/buildMiddleware/types.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,13 @@ export type SubMiddlewareBuilder = (
7171
ThunkDispatch<any, any, AnyAction>
7272
>
7373

74-
export type ApiMiddlewareInternalHandler<ReturnType = void> = (
74+
type MwNext = Parameters<ReturnType<Middleware>>[0]
75+
76+
export type ApiMiddlewareInternalHandler<Return = void> = (
7577
action: AnyAction,
76-
mwApi: SubMiddlewareApi & { next: Dispatch<AnyAction> },
78+
mwApi: SubMiddlewareApi & { next: MwNext },
7779
prevState: RootState<EndpointDefinitions, string, string>
78-
) => ReturnType
80+
) => Return
7981

8082
export type InternalHandlerBuilder<ReturnType = void> = (
8183
input: BuildSubMiddlewareInput

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/serializableStateInvariantMiddleware.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import isPlainObject from './isPlainObject'
22
import type { Middleware } from 'redux'
33
import { getTimeMeasureUtils } from './utils'
4+
import { isAction } from './createAction'
45

56
/**
67
* Returns true if the passed value is "plain", i.e. a value that is either
@@ -207,6 +208,10 @@ export function createSerializableStateInvariantMiddleware(
207208
!disableCache && WeakSet ? new WeakSet() : undefined
208209

209210
return (storeAPI) => (next) => (action) => {
211+
if (!isAction(action)) {
212+
return next(action)
213+
}
214+
210215
const result = next(action)
211216

212217
const measureUtils = getTimeMeasureUtils(
@@ -216,7 +221,10 @@ export function createSerializableStateInvariantMiddleware(
216221

217222
if (
218223
!ignoreActions &&
219-
!(ignoredActions.length && ignoredActions.indexOf(action.type) !== -1)
224+
!(
225+
ignoredActions.length &&
226+
ignoredActions.indexOf(action.type as any) !== -1
227+
)
220228
) {
221229
measureUtils.measureTime(() => {
222230
const foundActionNonSerializableValue = findNonSerializableValue(

0 commit comments

Comments
 (0)