React and TypeScript, v2

Typing Component State

Steve Kinney

Steve Kinney

React and TypeScript, v2

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

The "Typing Component State" 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 demonstrates how to type state properties. By default, TypeScript will infer the type based on the default state passed to the useState hook. This adds immediate type safety around values passed to the setter method.


Transcript from the "Typing Component State" Lesson

>> We figured out all the different kind of props we can pass in even up until children. The other kind of the two kinda core ways that React does its thing is props, and what's the other one? State, right? [SOUND] Okay, so what do we do about state?

So for that we're going to switch over to another example. And so I'm gonna just take a minute and switch gears. And we're gonna go to that accident counter. So again, I guess we start in a world where we have what is mostly a React component. Let's take a look at it in the browser.

We can count the days since our last JavaScript accident. Last time undefined was not a function, or we tried to call map on null or something along those lines. Right now it has no real state to speak of. And again, this is where we kinda double down on one of my core themes, which is when possible, TypeScript does try to stay out of your way.

So where do I use state? I'll say count.
>> How did you do that?
>> I have a snippet. I'll show it to you later. It just basically fills it in. The cool part is that it'll capitalize that C for me. I haven't figured how to make it also auto import useState if I haven't already, but that's one extra tab.

Yeah, there's a bunch of things that I can, I'm very lazy. So we've got this count and we give it a default value of 0. And guess what, it knows a count is. It knows it's a number. It knows I'm not using it anywhere. But it also knows that it's a number, right?

And that's pretty cool cuz now we can go ahead and find that 0. There it is. Swap it in and cool, whatever. But the nice part too is that, We can only set it to a number. If we look at actually setCount as well, that, and some of the ceremony around this, if it stresses you out, don't worry about it.

useState is really a wrapper around useReducer, so that's why it's dispatching actions. It just kind of uses this very basic action. In this case, we'll actually kinda accidentally rewrite this a little bit later, but it's saying, like, hey, we're gonna dispatch an action, for setState it's just a value, really.

And it's gotta be a number. This way, if we do try to set the count to a string, and let me tell you where we accidentally get strings when we think we're dealing with numbers. One of my biggest pet peeves which is input type number, the event target value is a string, right?

And then also you know that you can add two strings together and it'll concatenate them, right? And so the nice part is you will now have to become immediately aware of it while also becoming blissfully unaware that that's a problem. Because since you could only set it to a number, if you ever accidentally take event target value which happens to be a string and try to use setCount, as if there was a form field towards the bottom here for no reason whatsoever, right?

It will immediately catch that for you.
>> Did you know about input.value as number? Or instead of doing .value, you can do value as number, which is nice. I'm not gonna do what I have planned here, which is to parse into it or whatever objective is number, we're gonna do that instead.

I'm gonna live learn about value that as number. What's the support on that?
>> Great.
>> Awesome, I'm into it. See, this is why I come out here so I can learn things.
>> I'll double check in the meantime,
>> All right, we'll have live updates from Mark on the support for eventTargetValue.asNumber.

>> Yeah, it's clean across the board.
>> Clean across the board. So we've got this onClick where I can say that when that happens, we wanna say, Say count is count + 1. And it can only take a number as I said, for some reason I decide that, They won't let me set it to a string, right?

And so I instantly get caught. Cuz not knowing about eventTarget.asValue, I have made this mistake before, right? And yeah, I catch it pretty quickly, but it does involve me going to the browser, clicking a button. You don't really know what in these apps look like other than these moments that I flashed them on the screen.

Because mostly I'm getting all my feedback in the editor itself. setState also takes a function which I really love. And again, it knows already that this value is count. Yeah.
>> Does it know that because you put 0 on the useState?
>> Yep, yep, which you're setting up a nice segue for the next section.

It's like, what happens if I don't have a value yet, right, or other situations? When TypeScript can't figure stuff out for us, is when we have to step in, and we'll talk about what those cases are and how to step in. Yeah.
>> Quick question. So you're explicitly taking count in and setCount.

Is it an equivalent to prevent race conditions around previous state kinda thing?
>> Basically, it's also nice cuz it gives me a bunch of options, right? So the question was, does this prevent a race condition? If I had a fictitious, Count + 1, and then you know what?

Let's just do it three more times. Do you know what my new count will be?
>> 1.
>> 1, right? Because closure state, count was at 0. So it's like 0 plus 1, okay? 0 plus 1, okay? 0 plus 1, okay, right. And that seems inefficient. But this is not the workshop on React performance.

This is one on TypeScript. But yeah, so if I did this on the other hand, If I am in any way a 10x developer is because my multi cursor skills are incredibly strong. So this case, it'll be like cool, 0 plus 1 is 1, then it'll pass that value in again.

It'll be 2, it'll be 3, right? And so the other nice part is that I could, the reason I typically use it, I'm not usually super worried about the race conditions. The reason I will use it is, it's super easy to test, Not having to mount an entire, at this point, I have to say that's the number.

Cuz I've given TypeScript just no clue what's going on here. Pulling those functions out, if they're a little bit more complicated than incrementing a number. This is a JavaScript function. JavaScript functions are very easy to test. I put a parameter in, I look at what the return value is, and I make sure it's what I expect.

So if I have more complicated logic, I'll also use that function syntax so that I don't have to mount a component and fake click on things. I will just pull that out and test it like that. Cool, but everything is handled for us and life is good.

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