Make switch statements super type safe with the never type
The problem
The following code is a simple reducer for a counter component. It contains a switch
statement over a union type which is pretty type safe:
type Increment = {
type: "increment";
incrementStep: number;
};
type Decrement = {
type: "decrement";
decrementStep: number;
};
type Actions = Increment | Decrement;
const reducer = (state: State, action: Actions): State => {
switch (action.type) {
case "increment":
return { count: state.count + action.incrementStep };
case "decrement":
return { count: state.count - action.decrementStep };
}
};
How can we make this even more type safe? What if we get a new requirement for the counter to be reset? That would mean that a new action is added to the Actions
type. When we add the new action, how can we get the TypeScript compiler to remind us that a new branch in the switch
statement needs to be implemented?
The solution
What if we could tell the TypeScript compiler that the default
branch in the switch
statement should never be reached? Well we can do just that with the never
type!
Let’s examine what the type of action
would be in the default
branch:
const reducer = (state: State, action: Actions): State => {
switch (action.type) {
case "increment":
return { count: state.count + action.incrementStep };
case "decrement":
return { count: state.count - action.decrementStep };
default:
action;
}
};
It is of type never
!
So, if we create a dummy function that took in a parameter of type never
that is called in the default
switch
branch, maybe the TypeScript compiler would error if it reached there …
const reducer = (state: State, action: Actions): State => {
switch (action.type) {
case "increment":
return { count: state.count + action.incrementStep };
case "decrement":
return { count: state.count - action.decrementStep };
default:
neverReached(action);
}
};
const neverReached = (never: never) => {};
Let’s add a Reset
action and give this a try:
type Reset = {
type: "reset";
to: number;
};
type Actions = Increment | Decrement | Reset;
The TypeScript compiler errors as we hoped. Neat!
Wrap up
Calling a dummy function that has a parameter of type never
is neat way to get the TypeScript compiler to warn us if an area of our program is reached that shouldn’t be. It’s a nice touch in a switch
statement over a union type so that we are reminded to implement an additional branch if the union type is ever changed.
Marius Schulz has a great post on the never
type if you want to learn more about it.
If you to learn more about TypeScript, you may find my free TypeScript course useful: