If you enjoyed my post on type guards, this one might tickle your fancy. We're going to talk about how to build a type-safe reducer. Now, I use these for redux reducers, but these principles could apply to any function.
Let's start by typing some actions.
You'll notice we've created two action types
LearnSpell. Each of these has a
type and a
payload of each however is a different shape. In this case it's an object with a single key, but you can imagine a much more complex scenario.
Now at the bottom we have a type called
WizardActions. This is what's called a discriminated union. What this means is that we can take an argument of type
WizardActions and it will be exactly one the types in the union. Let's look at some more code to elaborate.
We now have a reducer that takes a
state and an
action and returns the current state. Don't worry, we'll handle these actions later. Now the
action argument is of type
WizardActions which means it's going to be of type
MakeFriend or of type
Let's expand on our reducer and keep going.
If you're used to redux, this should look familiar. We have a switch statement on the action type and we're handling each payload differently. For
MakeFriend actions we append a friend to the list of friends. For
LearnSpell actions we append a spell to the list of spells.
We actually don't need the default case because this is an exhaustive type-check, but it's still good to be defensive in case someone upstream uses an
any. It's also necessary if we integrate this with redux.
How does this work? Well Typescript is pretty smart. It figures out on it's own that checking
type will guarantee the payload is a certain shape. When we go to access that payload, it knows what properties to expect. If we attempted to check the
spell of a
MakeFriend action we would get a type error.
Let's have some fun now and call our reducer. First let's make some friends.
This reducer works how we expect at runtime; Harry meets Ron, then he meets Hermione. Let's learn some spells.
Now Harry learns Expelliarmus and Expecto Patronum!
If you want to know more about typing redux, I wrote an article about building a typed and code-split redux store.