Lesson Description
The "Unions & Template Literal Types" Lesson is part of the full, React and TypeScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:
Steve discusses the use of reducers with TypeScript and demonstrates how to utilize useState with type inference and explains the concept of unions to allow for multiple types within a single state. Steve also showcases the use of template strings as types to enforce specific shapes of data, highlighting the importance of type constraints for ensuring code safety.
Transcript from the "Unions & Template Literal Types" Lesson
[00:00:00]
>> Steve Kinney: All right, so we're going to talk about like one little side quest, and then we'll talk a little bit about reducers and how to use those with TypeScript because there's some really powerful things that you can do. I am a big reducer fan, right? And so I will also try to sell you on that, but I will show you an interesting and cool technique you can do with that. First, I want to show you something you can do with useState arguably and a whole bunch of other things that kind of doesn't fit in anywhere else, but does kind of fit in with what we were just talking about.
[00:00:37]
So now it seems like a good place to do it, which is, we were saying earlier, and I'm just going to make a bonus component just so that I don't shove it in somewhere else, and we'll say constant bonus component. So one of the things we talked about is that if TypeScript gets, like, if you give useState or whatever a value at first, it will use type inference to figure out what the type is going forward, and we'll see how that works a little bit more in a little bit, but the kind of cool thing is like you can also choose to give it a type in order to kind of like do some other interesting things again with that like self-documentation, like IntelliSense, filling stuff in for you.
[00:01:31]
So if we said something like const loading state and set loading state, and we said that equals useState loading, great, I have to at least import it, but sure. And then we said something here like set loading state, and we know that it's supposed to be a string, right? Because I gave it a string. So I can give it any string I want, right? I could say like, you know, loaded. That's fine, that's valid.
[00:02:24]
I could say potato, right, probably not super useful, but I can also do something like, you know, forget the E and that's a valid string too, right? One of the things you can do is the same way that you were, you know, this is effectively the same thing as we have now. The other fun thing that you can do is use what's called a union to say like, hey, not just any string, but like one of a few different types.
[00:02:55]
So the place that I end up using a union a lot sometimes is sometimes it depends, like I have a piece of my codebase or an ID might end up being a string or a number depending, you know, what thing I'm using on. So you could do something like string unioned with number, and now this piece of state could be set to a string or a number, and that's kind of ridiculous for this exact example, but like it does at least show you the general concept because there are a lot of things like, you know, for instance, a JSON value can be a string, number, boolean, null.
[00:03:36]
I think it can't actually be undefined, right? There's a whole bunch of things and it can't be a class, you know, it can be, it can either be string, number, boolean, null, an array of those, or an object where the keys are strings and the values are one of those, right? So on and so forth. But there are other interesting things we can do here where you can say like, this is can either be loading, error, or like, let's say loaded, right?
[00:04:09]
And now you see that I do get an error here, that that's not one of the states that we can set it to, right? And so now instead of saying like, because like when you just give it a string, it's like, oh, you gave it a string, so I guess this set state will take any kind of string, and that is totally true that it would, but in this case, we're saying, but not just any string, only one of these three strings, right?
[00:04:36]
And now you have that kind of like almost like a state machine or a knob that can be sent to one of three settings built into your application as well. And there are some other powerful takes on this, right? So if I named, let's change the state for a second, we're going to say that it's color and set color. Now, obviously I've got to change the like acceptable values, and we'll call this set color.
[00:05:13]
We could say that it is red, blue, or green. Obviously loading will not work in that case, and it will yell at me for both of these. And so now I could say blue, and again, the nice part of all of this stuff is that you get that fun IntelliSense, right? You not only get a little helpful warning if you got it wrong, but your chances of getting it wrong go down in this case as well. And to be clear, for those of us who might be getting a little help from our artificial friends, right, you are not only helping yourself and your co-workers, but like you're giving hints to the thing that gets stuff wrong all the time as well, and letting like either, you know, Copilot or Claude or like Codex help out as well.
[00:06:01]
And so you could do something like this. The other really powerful thing that you can do is, I don't remember which version of TypeScript, but it's been long enough that you don't have to worry about it. You can use template strings like you see in JavaScript as types. So we could say for instance that, you know, backticks just like a template string, you could say that it is like RGB number number number, and now this can only, this is obviously not blue is not valid, right?
[00:06:52]
But you could say now it can only be set to like RGB 25, 500, close to parentheses, now that's valid. So you can make sure that like you always have like a RGB. Now there's some limitations. You'll notice that I put number in here, 256 is totally valid. 1 million is totally valid, right? It's not going to be perfect in this case, and there are, you can get really tricky with it, but like I will warn you that if you try to get too sophisticated and like too recursive and stuff like that, TypeScript will be like, I hate you, I'm not doing this, right?
[00:07:27]
So you can't rely on it, and we will see ways that you can do stuff in a little bit. You can't rely on it like for really complicated stuff, but it is nice if it's like supposed to be like a hex code. Does it start with a pound sign, right? Or something along those lines. You can kind of like at least bring a little bit of information, right, along with that as well. And again, that helps in a lot of cases where if you did miss something or mess something up, you will get a helpful warning.
[00:07:59]
It's not going to be perfect, but there are some nice things that you can do in that sense, like if you know that all of the IDs are prefixed with a certain thing, you can make sure, right? And some things that are built into the browser will do this like by default, right? And so for instance, and like, I'll show you something cool, like we say ID equals crypto.randomUUID, right? If you hover over the type, it is effectively, this will work if you say like, if you assign it to a value that's expecting a string, it is technically a string.
[00:08:42]
However, if you assign a string that does not at least have some kind of like UUID-ish property to it, in that case, like you will at least get caught and like slapped on the wrist for not having, like, you know, effectively five strings with dashes, right? That said, you could say something like, something that's a string that is valid for being ID. The invalid is I'm not using this for anything, so if I do like a console log, I'll stop getting yelled at.
[00:09:17]
But like it is valid to be a string, but something that like this could not get reassigned to just potato. It would have to be something UUID-like. And so you can kind of like constrain a lot of the, if it was like, hey, we've got variants for a button, you can constrain it just like we did with the horizontal and vertical to just a union of horizontal and vertical. If it's for a set state, you can start to constrain it down to at least the right shape.
[00:09:42]
It's not going to get you perfectly there, but it will like at least catch some number of accidental edge cases. And again, it's that idea that your type system should help you with safety, but it should also help everyone on your team kind of at least like very, like without having to read and like know every documentation, figure out every single convention in your codebase, hopefully like push and guide everyone in the right direction.
[00:10:11]
Dustin, is there an official name for that specifying the shape of the type with strings? I think it's a template literal. I think it's the same name that is in like what we call it in JavaScript as well, like a template literal type, I think, template, not temporal, literal type as well, in that case. So yeah, you can see it for some things, you can use some amount of constraint around it, and it's super helpful.
[00:10:37]
And that kind of leads us in as we start to talk about reducers because we're going to use this thing that, you know, just having the like single straight, or union thing is like makes a union which is this or that, these template strings are useful, and they kind of get really useful when we get into using reducers where we might have, you know, a bunch of various like actions that might go through our reducer.
[00:11:06]
Like useReducer is a lightweight version of Redux that comes with React. Cool, cool, cool, I'm going to like, let's go put this code back. I'll commit it so that you have it and I'll push it up in a little bit as well, so we'll say that, and then we'll, I'm just going to return. What's cool about this is actually if I return it like this and I name it use color and export it. Now we theoretically have a hook that when it first gets used will be this color and you can only set it, if you look, it can only be set to other things.
[00:12:14]
So now I have a fun hook that is effectively a useState but has some of this type information like by default as well, which is kind of nice. So you can also say like, is, what did I choose? And so I might name this type RGB color. Cool, and we'll say the default color needs to be a RGB color, and we use it as the default value here. So now I have a hook, theoretically, that is just an abstraction over a useState that has a string, but like will have this type information by default, and like you can kind of build up those abstractions.
[00:12:57]
The other thing that it helps for in the like comprehensibility of your codebase is the name of the hook also implies a little bit of like what you're doing as well. And you can kind of build on top of this too, where you can say something like, okay, it's going to be this, or it'll be a different one where we'll do like pound sign string. I put that dollar sign in there just like, just like in JavaScript, where like you can't actually say six characters, you can with some really complicated sophisticated stuff, but like it will also get angrier with you as soon as you make stuff more complicated, and you run the risk of slowing stuff down too sometimes, right?
[00:13:40]
And you could put like HSL colors, you could have a set color hook that's like, hey, any kind of like valid CSS kind of color can pass in here, you can build that up. And then also if you pull in the other thing we talked about to really tie a bunch of stuff together, right, I don't necessarily care about those things because I get it from TypeScript like. You now can also not only have a hook that has a good name, but tells you the purpose of it and how it works and stuff along those lines as well.
[00:14:16]
And now this is a hook that can only be set to either something this kind of shape or something in a hex code-ish kind of shape as well. I have like some, I have this one file that I bring from project to project of like really fancy kind of like utility types that I will like drop into this project and we will talk about later as well because I think that might be fun and helpful too.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops