This is an alpha release for Redux 5.0. This release has has breaking types changes.
npm i redux@alpha
yarn add redux@alpha
Changelog
Reducer
type and PreloadedState
generic
We've made tweaks to the TS types to improve type safety and behavior. There are two big types changes in this alpha.
First, the Reducer
type now has a PreloadedState
possible generic:
type Reducer<S, A extends Action, PreloadedState = S> = (
state: S | PreloadedState | undefined,
action: A
) => S
Per the explanation in #4491 :
Why the need for this change? When the store is first created by createStore
, the initial state is set to whatever is passed as the preloadedState
argument (or undefined
if nothing is passed). That means that the first time that the reducer is called, it is called with the preloadedState
. After the first call, the reducer is always passed the current state (which is S
).
For most normal reducers, S | undefined
accurately describes what can be passed in for the preloadedState
. However the combineReducers
function allows for a preloaded state of Partial<S> | undefined
.
The solution is to have a separate generic that represents what the reducer accepts for its preloaded state. That way createStore
can then use that generic for its preloadedState
argument.
Previously, this was handled by a $CombinedState
type, but that complicated things and led to some user-reported issues. This removes the need for $CombinedState
altogether.
This change does include some breaking changes, but overall should not have a huge impact on users upgrading in user-land:
- The
Reducer
,ReducersMapObject
, andcreateStore
types/function take an additionalPreloadedState
generic which defaults toS
. - The overloads for
combineReducers
are removed in favor of a single function definition that takes theReducersMabObject
as its generic parameter. Removing the overloads was necessary with these changes, since sometimes it was choosing the wrong overload. - Enhancers that explicitly list the generics for the reducer will need to add the third generic.
Middleware action
and next
are typed as unknown
Currently, the next
parameter is typed as the D
type parameter passed, and action
is typed as theAction
extracted from the dispatch type. Neither of these are a safe assumption:
next
would be typed to have all of the dispatch extensions, including the ones earlier in the chain that would no longer apply.- Technically it would be mostly safe to type
next
as the default Dispatch implemented by the base redux store, however this would causenext(action)
to error (as we cannot promiseaction
is actually anAction
) - and it wouldn't account for any following middlewares that return anything other than the action they're given when they see a specific action.
- Technically it would be mostly safe to type
action
is not necessarily a known action, it can be literally anything - for example a thunk would be a function with no .type property (soAnyAction
would be inaccurate)
We've changed next
to be (action: unknown) => unknown
(which is accurate, we have no idea what next
expects or will return), and changes the action
parameter to be unknown
(which as above, is accurate).
What's Changed
- Type-check tests by @Methuselah96 in #4489
- Add PreloadedState generic by @Methuselah96 in #4491
- Type action and next as unknown by @EskiMojo14 in #4519
Full Changelog: v5.0.0-alpha.4...v5.0.0-alpha.5