Type-safe reducers — again.

Just like (almost) everyone else, I wrote my own wrapper for writing Redux reducers in Typescript in order to achieve type-safe reducers. It turns out, they’re not that much needed.

Disclaimer: the following won’t save you from writing boilerplate code. Just type-safety without wrappers.

Disclaimer 2: the following approaches are more suitable for NgRx users, as this uses classes to define actions. Please don’t hate me, Reacters. :)

Since Typescript 2.4 was released, string enums have finally become a thing, and I love using them for defining my action types. How do you write one, you’re asking? Simple. Let’s define our action types by using an enum called `TodoActionType`:

In order to continue, we need to define what a Todo is. We do so by using a class which we will be using as an interface, and we export it so that we can use it in our actions and in the reducer.

As you can see, we added three types. Now, we will be assigning each type to our actions.

Notice carefully: it is very important to mark the property type of our classes as readonly! We’ll see how the compiler will behave later in this article.

It’s time to write the reducer, using the action types we defined previously.

Even though this looks (and is!) a totally ordinary way of writing reducers with typescript, there are a few bits I want to highlight:

  • we define an enum for declaring our action types, but you don’t have to, use constants if you like
  • we define the property type of our classes using the readonly modifier, and this is crucial to make this work
  • we export our actions using an unique type called ActionTypes. It is fundamental that the action you want to use in your reducer is actually part of the union type.

Let’s see this in action using VS Code:

  • In the image below, I’m hovering the action.payload property. As you can see, the editor’s compiler is correctly displaying the value of the action.

Let’s now remove the readonly from one of our actions. As you can see in the image below, VS Code is telling me it cannot figure out the type of ou action in the switch branch where EDIT_TODO is the action type.

I hope this helps you avoid type-casting your actions and payloads for a smoother and better developers experience. It surely improved mine.

Happy Typescript!