Lesson Description

The "Zod Basics Solution" Lesson is part of the full, Fullstack TypeScript, v2 (feat. Zod) course featured in this preview video. Here's what you'd learn in this lesson:

Steve continues demonstrating the solution to the Zod Basics exercise. The solution to challenges 5 through 10 can be found in this lesson.

Preview
Close

Transcript from the "Zod Basics Solution" Lesson

[00:00:00]
>> Steve Kinney: So now, what if we wanted to refine something again, like in TypeScript, we don't get a lot of programmability right, but in JavaScript, you can program things. That's the selling point of JavaScript. So I've got a stupid little function here, which is, like, a way, like, is prime.

[00:00:18]
So if we wanted to have an only allowed to be prime numbers if the question is, why would you want this, I don't have an answer for you, right. At some point when you get onto challenge number five, you start the coffee starts hitting and you get creative all of a sudden.

[00:00:31]
So how do we go about doing that, we can go ahead and kind of take one of these things we saw before, so in this case, we want a prime number. So we can do that z.number, because they don't all have to be objects that said, if it was talking and typing at the same time, if it is just a number, you could argue, could I have just done type of number you could have, or type of equals, equals string.

[00:00:56]
Yes, but in this case, we can also do a few more powerful things and like, with the kind of putting it all together and nesting, it becomes interesting as well. So we'll say refine, the one good thing about copilot sometimes is that, like, if you've done this enough times in the same repo, because I you have a branch called main, I have a branch called dry run and practice and rehearsal and people will think I'm live coding, but I've done this a thousand times.

[00:01:23]
And so it has been trained on those on mine so if your suggestions are not nearly as good, it's because I have put in the hours. Cool, so I don't like that suggestion though actually. Okay, so we'll say is prime, so it'll first check to see if it's a number and then it will, like, pass that number through this function to make sure it is what you think it is.

[00:01:43]
So again, probably like, also useful for a string of a particular format, a string that matches a given regex, right. If we wanted to, I don't know if there's a built in helper for a zip code, but you could refine it to say, yeah, it should be a string.

[00:01:56]
It should have a length of five and also it should be your match this regex where it's five numbers, right? Or it's a zip code and I'm totally cool with it being five numbers or a hyphen, and then four more digits for a US, longer zip code, so on and so forth, right?

[00:02:16]
Like, the idea that you can, like, add that little extra stuff and again, trying at that point to save you a bunch of other things as well. The other thing that we'll do here is you can see this error is like, that's unique, right? And so like, we are throwing, if I just turn this into like, to throw, I think, can I take that out?

[00:02:44]
Like it obviously throws, but you can actually define more helpful error messages, why would you want to do this? Okay, it didn't validate on the API level and I want to send back a 400 with like actual helpful information. Formation that is not like me just leaking Zod error messages all over the place, right?

[00:03:02]
You could then include that error message in the 400 response, or you using as Zod schema for form validation, right? And you want to be able to say like, hey, for this input field, feel this is, email address must include whatever, right? That's not a valid URL, so on and so forth, so you can always like for a lot of these, also add in a message, right?

[00:03:38]
>> Steve Kinney: Cool and now they pass, all right? The transform we can kind of take a look at as well, which is, there are lots of things that we deal with that do not serialize into JSON super well, all right. And a lot of times we can't send full on JavaScript, objects over the wire, we can only send JSON that we can rehydrate back in there.

[00:04:04]
One of the things that usually comes up is a date and stuff along those lines, we do wanna make sure that at first it's a string, right? Because otherwise, what am I transforming, right? We could say, like, it's a string or a date already, I don't hate that idea but, like, I know that, like in this very fictitious example, it's coming back as from a JSON API.

[00:04:30]
And the cool thing is, because you already validated that it's a string, this value here is typed as a string. Right, you don't, it's not unknown it's like you've already figured out part of what it is you know, it's a string of some sort, right. So now typescript is already inferred that it is a string, and you can, kind of, like, move on with your life and so now you can, like, create a new date out of it, in this case as well.

[00:04:59]
And so because again, this is string, we hope that when we have new date, if that ends up with, like, something invalid, that we know that it was not a date, right. Because, like, we check to see, again, libraries like super JSON will also do something very similar for you, in terms of doing that coercion.

[00:05:18]
But it's pretty cool to be able to do yourself in a pinch if you don't want to pull in another library. So let's make sure that as I was talking and typing that I was not doing things that were silly, right? And so like if you check it out, we parse it and we know already, like if you look at the Typescript type, it has already inferred this is actually a date, right?

[00:05:38]
Just by the act of parsing it, and then we I check it 1000 more times. We can turn it back into a string, if we want to, great and like, if it's not a date, we throw with like, our like, our own special error messages, right? If it throws, that's how you know it didn't pass the validation, right.

[00:05:58]
All that safe parse really does is it puts your parsing in a try-catch block. That's it throwing is the act of failing, okay. There is a concept in TypeScript called a branded type, which is, and I'll kind of show you what that is in a second. So kind of just put the answer in the assignment on this one but I think it's because I wanted to show it at the time.

[00:06:27]
So we've got this user schema and then if we look it's like string and brand is user ID, which is, this is a TypeScript trick, which is, if you wanna say, I went through a lot of work to make sure this string is an email address or this string is a UUID.

[00:06:49]
Type script is like cool as a string, right? And so a lot of times, you will see this move, and there's a bunch of different ways to do. It's a string, and, like, some and there's a bunch of different ways to do it as a string and like, some weird metadata that doesn't like really exist, right?

[00:07:03]
And so now, if something says,
>> Steve Kinney: In this case, like,
>> Steve Kinney: X is a user ID, and I just give it a strength you'll see, it's like, hey, no, I needed to be a user ID, right? So you do think, I'm gonna check to see if that string was in fact a user ID and if it is then it'll match that type.

[00:07:32]
It's like there's not necessarily a sad thing, it's a little typescript trick to make sure, because, again, typescript only has A string type and this is a way to say, but my special string. But then you will always have to check to make sure it is first, right?

[00:07:45]
Even if it is a value from anywhere else in your code base, you will have to do some logic to confirm that it is in fact a UUID in this case but it works. Like we said before, there's this idea of pick, partial omit, why would you ever want to do this?

[00:08:07]
Very good reasons you might have let's yeah, we're gonna build a to do list, as I discussed, right? A task that's in the database has an ID, right? One that you are just creating, that you're sending to the API doesn't yet. So, like, you might only want parts of it, but then, like, what happens if we want to update the object?

[00:08:29]
Do I wanna make them pass in the entire full object again or do I say, like, give me a subset of the properties and I will update the object? So a lot of times they can all be optional, because if as long as I get an object, if it's all empty, then we do no updates.

[00:08:45]
If it's everything, we update everything, or maybe I want partial of everything, but like yo, the Id can't change right? Some of these tools make it a lot easier to do that so with a full user schema. In this case, what is this one expecting, so we've got the kind of earlier one that we wrote with the addresses so on and so forth.

[00:09:16]
>> Steve Kinney: Cool, use my address schema from earlier, isn't that nice of it, great and so here we've got that full schema and then a partial so say like, any like, give me a version of that's all optional, right? Because if we look here, we say, type user, I got, I.

[00:09:42]
>> Steve Kinney: You can see that, yeah, in this case, every part of this, except for the apartment number, is in this case,
>> Steve Kinney: Is in this case, like required, if I do the partial version of it, we can go ahead and say partial is just going to be full user schema.

[00:10:09]
You can see there's some methods on it, full user schema.partial, right? And so this is obviously, if you look, it looks complicated but if we look at the type that came out, if we say something like type partial user, now you can see that all of the properties are optional and they can be undefined, right, cool.

[00:10:35]
And so like, let's say we only wanted to show, like, the names and the addresses or something like that, right which is, it's in the test my font is very big right now, so we'll do like, full user schema.pick, and we'll say the properties that we want. And the nice part is, like, if you try to put a bogus one in there, it knows that that's not on the type, right.

[00:11:07]
Zod is doing under the hood, kind of updating types as it goes along you can't put in fields that aren't there, because it's already it knows that in that way, you're extending that full user schema from earlier cool or one without email. So it's, you know, dot .omit and so this will be everything but the email field, right?

[00:11:29]
So you can start out with like, you don't have to necessarily make a whole bunch of these by hand and update them all one at a time. So on and so forth you can kinda take a base and then derive and refine the other ones from that.
>> Steve Kinney: Cool, all right, then we have a fun one, this one I use far too often for this exact purpose, so I wasn't even particularly feeling creative at this point.

[00:11:55]
Which is sometimes you need, we said there was that email, there was a UUID, but sometimes I want something like a hex color, right. Or an RGB, or something along those lines, and I need to make sure it's that kind of string again, TypeScript is not helping me so much in that case.

[00:12:16]
So I can do something like this as well, so we'll say that this is a z.custom and you do have to give it some kind of hint into what it can expect cause like you're now, you're totally doing your own thing. You're like, it should be based on a string, right.

[00:12:37]
Make sure it's a string first, or assume it's a string, and then you know some way to say that it's a hex code. You could you know whether it's a regex, whether you want to check it into what other ways I think this has got to be three or six according to my tests.

[00:12:55]
He says, I'm live regexing now that's gonna go real well for me.
>> Steve Kinney: No, I didn't cool that's between three and six that's like live regexing reg got me. We'll say either 3 or 6 and so now this will verify that it is, it'll work on, three digit hex color.

[00:13:31]
It will work on a six digit hexadecimal, hex color, but it will fail if it doesn't have all the various things. You could do this same thing for like, RGB colors, anything in your code base where it's like, it's got to match this exact thing I got a lot of rules on what this thing ought to be.

[00:13:52]
The nice part is I can make this schema once and use it and reference it in all my other types and never think about this again. I now have a way all throughout my app to do this as well and like previously, if I was just, using a type guard function, I would probably have to validate all the time all over the place, is this actually a hex color?

[00:14:12]
Right, now I can say that if the large object passes because it will automatically be typed as a hex color in this case.
>> Audience 1: What does that get inferred into?
>> Steve Kinney: I'm pretty sure this one will get inferred as a string, and I had to brand it, so that's a great question let's see if I can do it live, let's test me.

[00:14:34]
And so, it is a string, but I think I can do a brand, yeah. And give it the brand of a hex color, and now it is accepted wherever hex colors are accepted it is like, it obviously is also a string, right? And so anything that accepts a string will accept this hex color and then anything that's like, no, no, no, no.

[00:14:55]
It's got to be a hex color, this is now accepted wherever hex colors are accepted, right? So you can do that branding very easily as well, that's just a utility method. You saw the other way that I could do in the comments as well but incredibly powerful pattern just for just general typescript use cases, all right?

[00:15:16]
And then finally, like this one, we will probably just hand away over a little bit, because it is a culmination of a bunch of things, but the ability to, kind of, like, pull them all together and have a bunch of different pieces that you use that you can then make useful as well.

[00:15:35]
Let's just look at that one, because I think watching me type that is like, not that fun, so, yeah,
>> Steve Kinney: So in this case, like, we can break it out to being like, okay, username with the arbitrary rules that I made of like four to 16 characters, passwords gotta be a string that is minimum eight, right?

[00:15:59]
And then I can test to say it has to have at least one digit in it obviously. You can take this to its natural conclusion as well and then you can say what error message it should throw if that didn't happen again, you do have some of these built in ones.

[00:16:13]
We can take a look at the sidebar in the docs, there's email there's definitely IP address, UUID-URL. Those are the only ones I've ever used, so there's probably more too, yeah, and a birth date is again, we're gooing to make sure it's a date. I could have probably grabbed that date, one from earlier as well and yeah, this is the same one we saw, and then this registration form is just basically built out of these other schemas, right?

[00:16:39]
So I don't have to do this all the time, I can get some of those primitives in place and move on with my life.

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