You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/api/createSlice.mdx
+14-5Lines changed: 14 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -304,16 +304,25 @@ Typing for the `create.asyncThunk` works in the same way as [`createAsyncThunk`]
304
304
305
305
A type for `state` and/or`dispatch`_cannot_beprovidedaspartofthe`ThunkApiConfig`, asthiswouldcausecirculartypes.
306
306
307
-
Instead, itisnecessarytoassertthetypewhenneeded.
307
+
Instead, itisnecessarytoassertthetypewhenneeded-`getState() as RootState`. Youmayalsoincludeanexplicitreturntypeforthepayloadfunction as well, in order to break the circular type inference cycle.
Copy file name to clipboardExpand all lines: docs/api/getDefaultMiddleware.mdx
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -55,7 +55,7 @@ const store = configureStore({
55
55
// Store has all of the default middleware added, _plus_ the logger middleware
56
56
```
57
57
58
-
It is preferable to use the chainable `.concat(...)` and `.prepend(...)` methods of the returned `Tuple` instead of the array spread operator, as the latter can lose valuable type information under some circumstances.
58
+
It is preferable to use the chainable `.concat(...)` and `.prepend(...)` methods of the returned `Tuple` instead of the array spread operator, as the latter can lose valuable TS type information under some circumstances.
Copy file name to clipboardExpand all lines: docs/introduction/getting-started.md
+2-3Lines changed: 2 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -34,7 +34,7 @@ you make your Redux code better.
34
34
35
35
### Create a React Redux App
36
36
37
-
The recommended way to start new apps with React and Redux is by using [our official Redux+TS template for Vite](https://github.com/reduxjs/redux-templates), or by creating a new Next.js project using [Next's `with-redux` template](https://github.com/vercel/next.js/tree/canary/examples/with-redux).
37
+
The recommended way to start new apps with React and Redux Toolkit is by using [our official Redux Toolkit + TS template for Vite](https://github.com/reduxjs/redux-templates), or by creating a new Next.js project using [Next's `with-redux` template](https://github.com/vercel/next.js/tree/canary/examples/with-redux).
38
38
39
39
Both of these already have Redux Toolkit and React-Redux configured appropriately for that build tool, and come with a small example app that demonstrates how to use several of Redux Toolkit's features.
40
40
@@ -85,8 +85,7 @@ yarn add react-redux
85
85
</TabItem>
86
86
</Tabs>
87
87
88
-
It is also available as a precompiled UMD package that defines a `window.RTK` global variable.
89
-
The UMD package can be used as a [`<script>` tag](https://unpkg.com/@reduxjs/toolkit/dist/redux-toolkit.umd.js) directly.
88
+
The package includes a precompiled ESM build that can be used as a [`<script type="module">` tag](https://unpkg.com/@reduxjs/toolkit/dist/redux-toolkit.browser.mjs) directly in the browser.
Copy file name to clipboardExpand all lines: docs/migrations/1.x-to-2.x.md
+48-22Lines changed: 48 additions & 22 deletions
Original file line number
Diff line number
Diff line change
@@ -12,15 +12,23 @@ toc_max_heading_level: 4
12
12
13
13
# Migrating 1.x → 2.x
14
14
15
+
:::tip What You'll Learn
16
+
17
+
- What's changed in Redux Toolkit 2.0 and Redux core 5.0, including breaking changes and new features
18
+
19
+
:::
20
+
15
21
## Introduction
16
22
17
23
Redux Toolkit has been available since 2019, and today it's the standard way to write Redux apps. We've gone 4+ years without any breaking changes. Now, RTK 2.0 gives us a chance to modernize the packaging, clean up deprecated options, and tighten up some edge cases.
18
24
19
25
Redux Toolkit 2.0 is accompanied by major versions of all the other Redux packages: Redux core 5.0, React-Redux 9.0, Redux Thunk 3.0, and Reselect 5.0.
20
26
21
-
This page lists known potentially breaking changes in Redux Toolkit 2.0 and Redux core 5.0, as well as new features in Redux Toolkit 2.0. As a reminder, you should not need to actually install or use the core `redux` package directly - RTK wraps that, and re-exports all methods and types.
27
+
This page lists known potentially breaking changes in Redux Toolkit 2.0 and Redux core 5.0, as well as new features in Redux Toolkit 2.0. As a reminder, **you should not need to actually install or use the core `redux` package directly** - RTK wraps that, and re-exports all methods and types.
28
+
29
+
In practice, **most of the "breaking" changes should not have an actual effect on end users, and we expect that many projects can just update the package versions with very few code changes needed**.
22
30
23
-
In practice, **most of the "breaking" changes should not have an actual effect on end users**. The changes most likely to need app code updates are:
31
+
The changes most likely to need app code updates are:
24
32
25
33
-[Object syntax removed for `createReducer` and `createSlice.extraReducers`](#object-syntax-for-createsliceextrareducers-and-createreducer-removed)
26
34
-[`configureStore.middleware` must be a callback](#configurestoremiddleware-must-be-a-callback)
@@ -66,6 +74,20 @@ We've always specifically told our users that [actions and state _must_ be seria
66
74
67
75
In practice, this was already true 99.99% of the time and shouldn't have any effect on users (especially those using Redux Toolkit and `createSlice`), but there may be some legacy Redux codebases that opted to use Symbols as action types.
68
76
77
+
#### `createStore` Deprecation
78
+
79
+
In [Redux 4.2.0, we marked the original `createStore` method as `@deprecated`](https://github.com/reduxjs/redux/releases/tag/v4.2.0). Strictly speaking, **this is _not_ a breaking change**, nor is it new in 5.0, but we're documenting it here for completeness.
80
+
81
+
**This deprecation is solely a _visual_ indicator that is meant to encourage users to [migrate their apps from legacy Redux patterns to use the modern Redux Toolkit APIs](https://redux.js.org/usage/migrating-to-modern-redux)**. The deprecation results in a visual strikethrough when imported and used, like ~~`createStore`~~, but with _no_ runtime errors or warnings.
82
+
83
+
**`createStore` will continue to work indefinitely, and will _not_ ever be removed**. But, today we want _all_ Redux users to be using Redux Toolkit for all of their Redux logic.
84
+
85
+
To fix this, there are three options:
86
+
87
+
-**[Follow our strong suggestion to switch over to Redux Toolkit and `configureStore`](https://redux.js.org/usage/migrating-to-modern-redux)**
88
+
- Do nothing. It's just a visual strikethrough, and it doesn't affect how your code behaves. Ignore it.
89
+
- Switch to using the `legacy_createStore` API that is now exported, which is the exact same function but with no `@deprecated` tag. The simplest option is to do an aliased import rename, like `import { legacy_createStore as createStore } from 'redux'`
90
+
69
91
<divclass="typescript-only">
70
92
71
93
#### Typescript rewrite
@@ -78,6 +100,26 @@ Redux core v5 is now built from that TS-converted source code. In theory, this s
78
100
79
101
Please report any unexpected compatibility issues on [Github](https://github.com/reduxjs/redux/issues)!
80
102
103
+
#### `AnyAction` deprecated in favour of `UnknownAction`
104
+
105
+
The Redux TS types have always exported an `AnyAction` type, which is defined to have `{type: string}` and treat any other field as `any`. This makes it easy to write uses like `console.log(action.whatever)`, but unfortunately does not provide any meaningful type safety.
106
+
107
+
We now export an `UnknownAction` type, which treats all fields other than `action.type` as `unknown`. This encourages users to write type guards that check the action object and assert its _specific_ TS type. Inside of those checks, you can access a field with better type safety.
108
+
109
+
`UnknownAction` is now the default any place in the Redux source that expects an action object.
110
+
111
+
`AnyAction` still exists for compatibility, but has been marked as deprecated.
112
+
113
+
Note that [Redux Toolkit's action creators have a `.match()` method](https://redux-toolkit.js.org/api/createAction#actioncreatormatch) that acts as a useful type guard:
114
+
115
+
```ts
116
+
if (todoAdded.match(someUnknownAction)) {
117
+
// action is now typed as a PayloadAction<Todo>
118
+
}
119
+
```
120
+
121
+
You can also use the new `isAction` util to check if an unknown value is some kind of action object.
122
+
81
123
#### `Middleware` type changed - Middleware `action` and `next` are typed as `unknown`
82
124
83
125
Previously, the `next` parameter is typed as the `D` type parameter passed, and `action` is typed as the `Action` extracted from the dispatch type. Neither of these are a safe assumption:
@@ -88,6 +130,8 @@ Previously, the `next` parameter is typed as the `D` type parameter passed, and
88
130
89
131
We've changed `next` to be `(action: unknown) => unknown` (which is accurate, we have no idea what `next` expects or will return), and changed the `action` parameter to be `unknown` (which as above, is accurate).
90
132
133
+
In order to safely interact with values or access fields inside of the `action` argument, you must first do a type guard check to narrow the type, such as `isAction(action)` or `someActionCreator.match(action)`.
134
+
91
135
This new type is incompatible with the v4 `Middleware` type, so if a package's middleware is saying it's incompatible, check which version of Redux it's getting its types from!
92
136
93
137
#### `PreloadedState` type removed in favour of `Reducer` generic
@@ -119,24 +163,6 @@ This change does include some breaking changes, but overall should not have a hu
119
163
- The overloads for `combineReducers` are removed in favor of a single function definition that takes the `ReducersMapObject` as its generic parameter. Removing the overloads was necessary with these changes, since sometimes it was choosing the wrong overload.
120
164
- Enhancers that explicitly list the generics for the reducer will need to add the third generic.
121
165
122
-
#### `AnyAction` deprecated in favour of `UnknownAction`
123
-
124
-
The Redux TS types have always exported an `AnyAction` type, which is defined to have `{type:string}` and treat any other field as `any`. This makes it easy to write uses like `console.log(action.whatever)`, but unfortunately does not provide any meaningful type safety.
125
-
126
-
We now export an `UnknownAction` type, which treats all fields other than `action.type` as `unknown`. This encourages users to write type guards that check the action object and assert its _specific_ TS type. Inside of those checks, you can access a field with better type safety.
127
-
128
-
`UnknownAction` is now the default any place in the Redux source that expects an action object.
129
-
130
-
`AnyAction` still exists for compatibility, but has been marked as deprecated.
131
-
132
-
Note that [Redux Toolkit's action creators have a `.match()` method](https://redux-toolkit.js.org/api/createAction#actioncreatormatch) that acts as a useful type guard:
133
-
134
-
```ts
135
-
if (todoAdded.match(someUnknownAction)) {
136
-
// action is now typed as a PayloadAction<Todo>
137
-
}
138
-
```
139
-
140
166
</div>
141
167
142
168
### Toolkit only
@@ -499,11 +525,11 @@ In practice, we hope these are reasonable tradeoffs. Creating thunks inside of `
Copy file name to clipboardExpand all lines: docs/rtk-query/usage-with-typescript.mdx
+26Lines changed: 26 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -390,6 +390,32 @@ const api = createApi({
390
390
})
391
391
```
392
392
393
+
### Typing `dispatch` and `getState`
394
+
395
+
`createApi` exposes the standard Redux `dispatch` and `getState` methods in several places, such as the `lifecycleApi` argument in lifecycle methods, or the `baseQueryApi` argument passed to `queryFn` methods and base query functions.
396
+
397
+
Normally, [your application infers `RootState` and `AppDispatch` types from the store setup](../tutorials/typescript.md#define-root-state-and-dispatch-types). Since `createApi` has to be called prior to creating the Redux store and is used as part of the store setup sequence, it can't directly know or use those types - it would cause a circular type inference error.
398
+
399
+
By default, `dispatch` usages inside of `createApi` will be typed as `ThunkDispatch`, and `getState` usages are typed as `() => unknown`. You will need to assert the type when needed - `getState() as RootState`. You may also include an explicit return type for the function as well, in order to break the circular type inference cycle:
400
+
401
+
```ts no-transpile
402
+
const api =createApi({
403
+
baseQuery,
404
+
endpoints: (build) => ({
405
+
getTodos: build.query<Todo[], void>({
406
+
async queryFn() {
407
+
// highlight-start
408
+
// Cast state as `RootState`
409
+
const state =getState() asRootState
410
+
// highlight-end
411
+
const text =state.todoTexts[queryFnCalls]
412
+
return { data: [{ id: `${queryFnCalls++}`, text }] }
413
+
},
414
+
}),
415
+
}),
416
+
})
417
+
```
418
+
393
419
### Typing `providesTags`/`invalidatesTags`
394
420
395
421
RTK Query utilizes a cache tag invalidation system in order to provide [automated re-fetching](./usage/automated-refetching.mdx) of stale data.
As TS cannot combine two string literals (`slice.name`and the key of `actionMap`) into a new literal, all actionCreators created by `createSlice` are of type 'string'. This is usually not a problem, as these types are only rarely used as literals.
329
+
`createSlice` generates action type strings by combining the `name`field from the slice with the field name of the reducer function, like `'test/increment'`. This is strongly typed as the exact value, thanks to TS's string literal analysis.
330
330
331
-
In most cases that `type` would be required as a literal, the `slice.action.myAction.match`[type predicate](https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-type-predicates) should be a viable alternative:
331
+
You can also use the `slice.action.myAction.match`[type predicate](https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-type-predicates) should be a viable alternative:
// `action` is narrowed down to the type `PayloadAction<number>` here.
@@ -408,6 +411,59 @@ type AtLeastOne<T extends Record<string, any>> = keyof T extends infer K
408
411
typeAtLeastOneUserField=AtLeastOne<User>
409
412
```
410
413
414
+
### Typing Async Thunks Inside `createSlice`
415
+
416
+
As of 2.0, `createSlice` allows [defining thunks inside of `reducers` using a callback syntax](../api/createSlice.mdx/#the-reducers-creator-callback-notation).
417
+
418
+
Typing for the `create.asyncThunk` method works in the same way as [`createAsyncThunk`](#createasyncthunk), with one key difference.
419
+
420
+
A type for `state` and/or `dispatch` _cannot_ be provided as part of the `ThunkApiConfig`, as this would cause circular types.
421
+
422
+
Instead, it is necessary to assert the type when needed - `getState() asRootState`. You may also include an explicit return type for the payload function as well, in order to break the circular type inference cycle.
If you need to reuse reducer logic, it is common to write ["higher-order reducers"](https://redux.js.org/recipes/structuring-reducers/reusing-reducer-logic#customizing-behavior-with-higher-order-reducers) that wrap a reducer function with additional common behavior. This can be done with `createSlice` as well, but due to the complexity of the types for `createSlice`, you have to use the `SliceCaseReducers` and `ValidateSliceCaseReducers` types in a very specific way.
0 commit comments