Reputation: 4353
I'm using createSlice
together with useReducer
.
I'd like the dispatch to be typed properly, that is React.Dispatch<ReducerActions>
.
createSlice
?The following does not work, it resolves to AnyAction
... which is understandable I'd say, as all actions pass through all reducers.
Dispatch<Parameters<typeof slice["reducer"]>[1]>
Upvotes: 7
Views: 6170
Reputation: 42218
createSlice
stores the action creators as a keyed object in the property actions
. What we are looking for is the union of the return types of all action creators. We will use a mapped type to get this.
type SliceActions<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => infer A ? A : never;
}[keyof T]
type ActionTypes = SliceActions<typeof slice.actions>
I used the counter example from the doc in this Playground Link and the value of ActionTypes
evaluated to:
type ActionTypes = {
payload: undefined;
type: "counter/increment";
} | {
payload: undefined;
type: "counter/decrement";
} | {
payload: number;
type: "counter/incrementByAmount";
}
When I first wrote this answer (October 2020) the action types were inferred as type: string
rather than specific string literals. With the latest versions of Redux Toolkit and TypeScript (as of March 2023) you actually get the exact types!
Upvotes: 7
Reputation: 31
Based on Linda type, There is another way for better typing:
const storeSlice = createSlice({
//...
reducers: {
fetchData: (state, action: PayloadAction<string>) => {
//...
onFetchFailed: (state, action: PayloadAction<string>) => {
//...
},
},
});
type SliceActions<T> = {
[K in keyof T]: {type: K; payload: T[K] extends (...args: infer P) => void ? P[0] : never};
}[keyof T];
/*
ActionTypes = {
type: "fetchData";
payload: string;
} | {
type: "onFetchFailed";
payload: string;
}
*/
type ActionTypes = SliceActions<typeof storeSlice.actions>;
Upvotes: 3