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
* Docs: add info on how to type Meta in `createSlice`
* Docs: better example for signal.addEventListener
* docs: TS usage for `createAsyncThunk`
* docs: TS docs for `createEntityAdapter`
* Edit new TS usage docs
Co-authored-by: Mark Erikson <[email protected]>
### Alternative to using a literally-typed `action.type`
112
112
113
-
If you are using `action.type` as discriminator on a discriminated union, for example to correctly type your payload in `case` statements, you might be interested in this alternative:
113
+
If you are using `action.type` as a discriminator on a discriminated union, for example to correctly type your payload in `case` statements, you might be interested in this alternative:
114
114
115
115
Created action creators have a `match` method that acts as a [type predicate](https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-type-predicates):
116
116
@@ -128,7 +128,7 @@ This `match` method is also very useful in combination with `redux-observable` a
128
128
129
129
## `createReducer`
130
130
131
-
The default way of calling `createReducer` would be with a map object, like this:
131
+
The default way of calling `createReducer` would be with a "lookup table" / "map object", like this:
132
132
133
133
```typescript
134
134
createReducer(0, {
@@ -159,7 +159,7 @@ As an alternative, RTK includes a type-safe reducer builder API.
159
159
160
160
Instead of using a simple object as an argument to `createReducer`, you can also use a callback that receives a `ActionReducerMapBuilder` instance:
You might have noticed that it is not a good idea to pass your `SliceState` type as a generic to `createSlice`. This is due to the fact that in almost all cases, follow-up generic parameters to `createSlice` need to be inferred, and TypeScript cannot mix explicit declaration and inference of generic types within the same "generic block".
219
219
220
-
Instead, you can use the construct`initialState: myInitialState as SliceState`.
220
+
The standard approach is to declare an interface or type for your state, create an initial state value that uses that type, and pass the initial state value to `createSlice. You can also use the construct`initialState: myInitialState as SliceState`.
initialState, // type SliceState is inferred for the state of the slice
231
+
reducers: {}
232
+
})
233
+
234
+
// Or, cast the initial state as necessary
235
+
createSlice({
236
+
name: 'test2',
227
237
initialState: { state: 'loading' } asSliceState,
228
-
reducers: {
229
-
// ...
230
-
}
238
+
reducers: {}
231
239
})
232
240
```
233
241
234
242
which will result in a `Slice<SliceState, ...>`.
235
243
236
-
### On the "type" property of slice action Reducers
244
+
### Defining Action Contents with `prepare` Callbacks
237
245
238
-
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.
246
+
If you want to add a `meta` or `error` property to your action, or customize the `payload`of your action, you have to use the `prepare` notation.
239
247
240
-
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 prove as a viable alternative:
248
+
Using this notation with TypeScript looks like this:
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.
274
+
275
+
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:
276
+
277
+
```ts {10}
243
278
const slice =createSlice({
244
279
name: 'test',
245
280
initialState: 0,
@@ -259,7 +294,44 @@ If you actually _need_ that type, unfortunately there is no other way than manua
259
294
260
295
### Type safety with `extraReducers`
261
296
262
-
Like in `createReducer`, the `extraReducers` map object is not easy to fully type. So, like with `createReducer`, you may also use the "builder callback" approach for defining the reducer object argument. See [the `createReducer` section above](#createreducer) for an example.
297
+
Reducer lookup tables that map an action `type` string to a reducer function are not easy to fully type correctly. This affects both `createReducer` and the `extraReducers` argument for `createSlice`. So, like with `createReducer`, [you may also use the "builder callback" approach](#building-type-safe-reducer-argument-objects) for defining the reducer object argument.
298
+
299
+
This is particularly useful when a slice reducer needs to handle action types generated by other slices, or generated by specific calls to `createAction` (such as the actions generated by [`createAsyncThunk`](../api/createAsyncThunk.md)).
In the most common use cases, you should not need to explicitly declare any types for the `createAsyncThunk` call itself.
398
+
399
+
Just provide a type for the first argument to the `payloadCreator` argument as you would for any function argument, and the resulting thunk will accept the same type as input parameter.
400
+
The return type of the `payloadCreator` will also be reflected in all generated action types.
The second argument to the `payloadCreator` is a `thunkApi` object containing references to the `dispatch`, `getState`, and `extra` arguments from the thunk middleware. If you want to use these from within the `payloadCreator`, you will need to define some generic arguments, as the types for these arguments cannot be inferred. Also, as TS cannot mix explicit and inferred generic parameters, from this point on you'll have to define the `Returned` and `ThunkArg` generic parameter as well.
423
+
424
+
To define the types for these arguments, pass an object as the third generic argument, with type declarations for some or all of these fields: `{dispatch?, state?, extra?}`.
While this notation for `state`, `dispatch` and `extra` might seem uncommon at first, it allows you to provide only the types for these you actually need - so for example, if you are not accessing `getState` within your `payloadCreator`, there is no need to provide a type for `state`.
448
+
449
+
## `createEntityAdapter`
450
+
451
+
Typing `createEntityAdapter` only requires you to specify the entity type as the single generic argument.
452
+
453
+
The example from the `createEntityAdapter` documentation would look like this in TypeScript:
454
+
455
+
```ts {7}
456
+
interfaceBook {
457
+
bookId:number
458
+
title:string
459
+
// ...
460
+
}
461
+
462
+
const booksAdapter =createEntityAdapter<Book>({
463
+
selectId: book=>book.bookId,
464
+
sortComparer: (a, b) =>a.title.localeCompare(b.title)
0 commit comments