Reputation: 31495
I've tried to find a definitive answer do this, but haven't found one yet.
There a question here on SO that answers how to implement an exhaustive switch
statement:
How do I check that a switch block is exhaustive in TypeScript?
And the answer is:
Write a function that takes never
as a parameter, returns never
and will throw when called with anything.
function assertUnreachable(x: never): never {
throw new Error("Didn't expect to get here");
}
And use it in your default
case:
switch (action.type) {
case "A": {
...
}
case "B": {
...
}
default: {
return assertUnreachable(action); // CAN'T USE action.type HERE BECAUSE action WILL BE never AND action.type WILL BE any
}
}
But I can't use it like this inside a reducer
. It will work as far as checking exhaustiveness for my reducer actions, but will throw during runtime because Redux will call it with its own internal actions, like, for example:
@@redux/INITh.b.0.x.q.h // THIS IS THE action.type
@@redux/PROBE_UNKNOWN_ACTIONe.7.b.o.p // THIS IS THE action.type
So what is the ideal way of handling exhaustiveness of a switch
statement inside a reducer?
Upvotes: 2
Views: 1245
Reputation: 67587
The right answer here is to not worry about this at all.
Even with that switch statement, your reducer will be called with other actions. So, trying to limit the exact set of actions doesn't really help.
The better approach is to use the createSlice
API from our official Redux Toolkit package, and let it define what actions you expect to handle in that particular slice.
Upvotes: 3
Reputation: 26094
I found a neat solution in Note on TypeScript's exhaustive type checks in scope of Redux's reducer. The solution is to:
function endReducer<T>(state: T, action: never): T {
return state;
}
function reducer(state: State, action: Actions) {
switch (action.type) {
case ...
default:
return endReducer(state, action);
}
}
Upvotes: 2