Check out a free preview of the full React and TypeScript, v2 course

The "Reducers with Explicit any" Lesson is part of the full, React and TypeScript, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Steve refactors the code to create a more complex reducer that manages both the count and draftCount states. This change introduces the "any" type for the action object, and the issues using "any" are discussed.


Transcript from the "Reducers with Explicit any" Lesson

>> Let's do a slightly more aggressive one. Before I use that use effect that I didn't wanna use to, or at least alluded to using a use effect to, okay, so listen to when the count changes, and then go ahead and update the DraftCount. I kind of said before, a lot of times it's easy to say, yo, one of these two things has changed, or they've clicked the Update Count button.

These things could happen, figure it out. Just because we're focused on TypeScript, I'm gonna pull in a reducer, kinda like in a cooking show when I pull the turkey out of the oven. I'm gonna pull in one and that is not necessarily where the problem in my code is gonna be.

But we'll look at it first, we'll talk about it, but watching me write this is probably not the best use of your time. I will be pulling in this any, which is a hint for where I get bitten later. [LAUGH] Just setting the scene now. So if we look, we've got this initial state, which I've given a type, you might call it counter state.

Just to keep the understanding of code, we're seeing for the first time a little bit simpler, and we'll have just a default object that we'll pass in as well. The cool part is I don't have to give state a type if it has a default value, right? In any TypeScript function, if something has a default value, TypeScript's like, let me guess, if you're saying that defaults to a number, it's probably a number.

Now if you wanna say it's a number or a string, you gotta step back in again, but as long as you've done the bare minimum, it will try to help you along the way. And all this really does is, again, because of, reducers follow the same rule as React does writ large, which is everything's got to be immutable, right?

And so with these we have the count and the draftCount. All right, cool. If increment comes in, increment the count and then set it to the newCount. We also wanted to update draftCount along with that every time. So we wanna say if that input field should change along with when I hit the buttons, decrement, reset, sets them both to zero.

I don't need to explain to you how a counter works. We also have one that's gonna take updateDraftCount. That's when they change the number in the input field, right? That's actually going to be one where we actually have what we might call a payload. One of the things that I'm gonna do is, and you don't have to do this, in Redux for instance, there is one rule for actions, is that all actions have a type property, right?

So, It's got to have a type. It's got to be some kind of, usually a string, if you like yourself. After that, in Redux, there are no rules. useReducer and React, it has even less rules, as you saw. I'm just tossing in a number, right? And it's like, that's cool.

I'm into it. And so it literally could be anything. Now a great way to have your teammates hate you is to just wing it with all these things. It's like, the pattern I like, there's something called flux standard actions. Redux being an implementation of flux, we don't have to talk about this.

Which is like basically having like fourish fields, two that we really care about, which is to say, definitely have to have a type. And then just to make it standard, having this payload property, which is everything you need to know about the thing that happened. They changed the value of that input field.

In payload, you would either put the new value or an object that had the keys and properties, right? That's better than, I wonder what properties. I wonder what the shape of this action is. It's just a convention. You don't have to do it. I'm going to do it because I do it right and because I'm teaching, and so it makes sense to follow some sort of convention rather than just making stuff up as I go along.

So we'll have actions in a payload. And so you'll see, if I go down into the reducer we'll bring in. So, should we update the count manually? Go look at the payload, which will be the new value, right? And everything will kind of work as well. This, obviously, as we all know, was written before I learned about event value as number, two hours ago.

So it does do some coercing of stuff as well. But let's pull this in cuz this is not my problematic code. So there's, other than there's just been a reducer, which is inherently typed, really, despite the fact that it doesn't look like it too much. So let's go ahead and let's remove all of my riffing.

And I'm gonna put this all in the same file just for clarity, normally you would break this out into its own file. But rather than watch me jump around between six different files, it's probably easier to keep it all in one place. So we've got this reducer, and again, what I would do and in some of the other example apps, probably have a bunch of tests than just passing the number two and then the accurate action with a type increment and then sees the number three comes out, right?

Then I have one that passes and decrement and sees that the number one comes out, so on and so forth. Super easy tests. You don't have to use React testing library to mount the component and click a bunch of stuff. You might choose to do that as well, but it's nice that you don't have to in this case.

Cool, and so he's angry at me, right? And that's good. I just pasted some code in, TypeScript is upset with me. Why? It's expecting an object. Now, this reducer expects an object that has a count and a draftCount. And it's like, yo, you left this old code in here when this was a zero.

I was like, yes, I did cuz I was talking to my friends while I was doing this, right? And instantly it catches that, so I don't have to embarrass myself in front of my friends and sit here flailing wildly, so that's good. So now we've got this and we can see automatically the count and draftCount.

That draftCount is any, and that was on purpose as I was setting you up to change stuff. But again, got bitten by it, so I'm telling you the story of how that happened to me. And then, setCount. Wow, setCount is now any. Right now, weirdly, hypothetically, if we changed this to a number for a moment.

Same type, string. payload is number, hypothetically. You'll notice, now, I can only dispatch the right things. Do you see how I'm about to get hurt, [LAUGH] right? Do you see what's about to happen to me here? One any threw away all the type safety of what came out of my reduce and what I could dispatch to it.

And as we learned about some of the other really nice stuff that TypeScript gives me, when I follow the rules and use reducer, we're gonna see how the damage is much worse and even we're probably thinking of right now. So we've got that in place, I've got that any in there.

And so, I was going about my business, I can go in here, obviously these are all bogus now. So what I can do is I can dispatch. We wanna call this, I was making a point that it was setCount but let's actually do the thing now. Well, dispatch, Could really go for some autocomplete now.

Well, I'm not gonna get any. Does anyone remember what the name of my increment action was? That seems good, yeah. Well, let me scroll up and look. I'm making a point. [LAUGH] Increment, whoa, you can see that I'm like, if it's the wizard behind the cloak, as soon as I don't have autocomplete working for me, I have a lot of empathy for every coding interview we have to do in this.

We don't need a payload on that object, but I don't really remember. Also you'll notice that I've once again made the mistake that I've made a thousand times, of course, multiple workshops I'll have, where I give increment decrement and decrement increment. Increment, I could go for some autocomplete.

Now, that wasn't even for show. That wasn't even me trying to make the point, that was literally me not knowing how to type while talking, despite the fact that I did it for a living for years. All right, for count, we needed to do, we'll still call it state now since it's two things.

It does know what this is at least. Well, it knows what a count is. Cool, we don't need this anymore since that will exist on state. Now, it will be in any type. What was the name of that one? Cool, and I can say, I'll show you what I did.

Typed action, And I typed action cuz I was doing actions and I was doing types and I was somewhat, I was just kinda in autopilot setting this thing up and not really thinking. Now, I don't need to explain how conditionals work to you to explain that if you were looking for an action type any and you pass in an object, that action is updateDraftCount.

It just falls right through all of these conditionals and you get back your initial state. And then you hit a button repeatedly, and nothing happens, right? Because you don't even get an error, the code works. It's just on a very nuanced version of what works is. We could take the event target value, so on and so forth.

But the point that I wanted to make is that having won any in there opted me out of type safety everywhere, right, effectively on dispatch at least. Made it so that I had to sit there and type every action by hand and look up and remember it, so on and so forth, right?

It's kind of like setting the stage of how life is now with one any, one innocuous any, just unlike literally one value, right, which is just simply the action, affected everything. And I lost, yeah, it was like ten minutes, but still, you know what? Enough of those ten minutes, and you're like, yeah, I can write some types.

So let's kinda look at how we might make that a little bit better, right, instead of doubling down and watching me fall all the way after you've seen where I got bitten by a real world mistake. Let's make this better

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now