React and TypeScript

React and TypeScript Refactoring with Utility Types

This course has been updated! We now recommend you take the React and TypeScript, v2 course.

Check out a free preview of the full React and TypeScript course:
The "Refactoring with Utility Types" Lesson is part of the full, React and TypeScript course featured in this preview video. Here's what you'd learn in this lesson:

Steve walks through refactoring the character cards from earlier in the course to use utility types. Some of the utility types used in this segment are keyof, Capitalize, and Exclude.

Get Unlimited Access Now

Transcript from the "Refactoring with Utility Types" Lesson

>> Do a little bit of refactoring just to see some of this in action. So, I am going to take the character cards that we saw earlier. Layer. And you can see that if I go into table row, We say, okay, we have this idea of a table row on that card and just to remind you what they look like.

[00:00:32] This is the table row over here. We have all the factors that are on one of these characters; alignment intelligence, strength, speed, so on and so forth. The table row or cell says give me a heading of a string and give me a value that is either a string, or a number.

[00:00:52] And that's cool, but like I would love if I could give myself some protection to not miss type, like literally misspell one of those rows. I want to like instead of being no pass in anything I wanna say no, I want to give you like one of the known.

[00:01:13] One of the known things that are going to be on that character type is defined if we look at it here. I believe it's in character information characters. Yeah. Like we know what's on a character object. I would love to only be able to pass in one of these.

[00:01:32] And not be able to like misspell something right, and so instead of going to character information. I could theoretically. Misspell alignment. I'm not gonna get any, there's no safety around that. I just hope that it's all fine. That's not great. I'd love to say like, hey, I can only make table rows that match to one of the types.

[00:01:56] Could I like had code that in? Yeah, but you can see how this could get unwieldy, right? You can see a world where hard coding in every possibility and then updating it throughout the codebase becomes problematic. What I might wanna do, it means I have to change stuff in two places.

[00:02:13] This code is not dry if I add a new property onto character type. I then also have to add that same property on to the table row props. That's not great. What I love to do is like, hey, look at the character type, and figure out what the properties are on that.

[00:02:31] And that should be the stuff I'm allowed to pass into the table row. That seems like better, right? So what would that look like for us? Let's take a look. Let's go into this table row. And we can pull in, we have character type available. Well we want to say instead of having been a string, had ABS string could be the key of character type.

[00:02:57] Right, so now this is technically broken and we'll figure why in a second. But you can see it's like, hey, but if you look at this heading is now, it's not just any string. It has to be named alignment, intelligence, strengths, get it. And we can pass it in.

[00:03:19] Now the problem is that I want them to be capitalized. And the type definition has them all lowercase. There are three ways I can handle this. I could make it uppercase in JavaScript programmatically inside the react component. I could use CSS. Or, I could just fix my types, which considering this as a course on TypeScript seems to be the most appropriate of the three.

[00:03:50] So we will go in, we'll go with that, so okay? What we do in this case, let's go back to the table row. We can use that we thought we had that capitalized before. So we could actually combine some of these. We can also say capitalize key character type.

[00:04:15] Yes, lint is angry at me, but we will see that it works. I'm no longer getting yelled at and you can look if you hover over it. As you can see that is now name alignments, so on and so forth, or any of these table rows. Now technically name is used here so if I wanted to be even more.

[00:04:37] I wanted to kind of combine even more this make sure that name wasn't included. I can also, there's two ways I could do it. I can do it with omit or I can do with exclude, let's try with exclude first. So we could take yeah Yeah, we can continue, this is a little exclude, Name.

[00:05:05] So now you can see that name is not included in that list. And we have, like I was giving this component to somebody else on my team to use, right? It's already enforcing a lot of that safety in there and a lot of the kinda constraints that make it used the way that it was designed to be used.

[00:05:22] And kind of again, help everyone to avoid just like silly little bugs. It'll happen before a deadline. Yeah, I know that these are all strings and numbers, but you could also say like, okay, go look at that type as well. And the value should only be one of the values that are in the object, so I could say, Character type.

[00:05:51] Right now we can see that this is really just a string or a number again. But now it's based off the type Instead of me hard coding it in myself. Alright, so now you have an exercise. This is all, yeah, this is a little too simple, but let's, go for it right.

[00:06:13] Like clearly it's all in the same file, but you can imagine how in a slightly larger code base, some of this might play out, which is. We have this idea of a user model. But it's got this idea of account ID, which maybe we don't want to let people use based on that model.

[00:06:36] So we won't have a type that is based on user model. But with all the properties that are on user model, except for account ID. And we don't want like yeah, could I copy and paste and remove a line I totally could write. But we want to have is a type that is based on this user model.

[00:06:53] And this might be our current user prompts in this case, but doesn't allow for account ID. That way we can't accidentally display it on the UI, or something along those lines.