
Lesson Description
The "Advanced Zod Uses Exercise" 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:
Students are instructed to solve more advanced Zod schema validation challenges involving lazy recursion and preprocessing.
Transcript from the "Advanced Zod Uses Exercise" Lesson
[00:00:00]
>> Steve Kinney: So then there are more advanced use cases. So why don't we spend another few minutes we're gonna dig into the other ones, because like, at that point, we will stop with the like training ground of Zod schemas, and we'll actually put it into practice. But I think like getting our sea legs under us and then taking a run at it in the real world app.
[00:00:19]
Application, we will be better prepared in our journey together. So like I said, before you've got my notes, you've got the docs, we'll do it together, and I'll show you some of my feels on what I thought of all of the advanced ones were the most useful. You might need other ones in there and have to like in your day-to-day life.
[00:00:40]
But these were from, again, the very scientific way that I reflected on who's hurt me at 2 in the morning by changing arrays into null back in engineers, it's never the tools. These are the ones that I find myself reaching for the most. So take a look and then we will try it out together.
[00:01:05]
>> Steve Kinney: All right, so we covered some of the basics together. There are, again, my small selection based on feels of what some of the more esoteric but useful enough that I felt compelled to include them. Schemas going through every single one of them would be boring, right? And so kinda take a look at a few of these.
[00:01:33]
One of the problems that we have is JavaScript is hard. Shocker, and so if we wanted to have a category that could have subcategories, we're gonna come up with a little bit of a problem, right? So I could try to do something, and that's because I kinda hit the answer in here as well.
[00:01:59]
No, don't give me the answer yet. I'm trying to make a point where we have an object, where the name is a string, and then like I said before, we can reference other schemas, right? And that is normally a AOK way to handle this, right?
>> Steve Kinney: Category schema.
[00:02:32]
>> Steve Kinney: The problem is not a Zod problem. The problem is JavaScript angry with me, right? It's like you can't use it before it was defined, because it's evaluating at this point before it assigns it there, right? So it's like, you can't use this cuz it's not defined yet, cuz you're currently in the process of defining it.
[00:02:55]
So we need to do is figure out a way to tell Zod to wait a second. Cuz you wait a second, then it will be defined. And so, again, the hint is hiding literally in plain sight. What we can do here is say z.lazy, which takes a function, right?
[00:03:17]
And just in the nature of the way that JavaScript works this will be defined, and then it will call the function, right? And so at that point, category schema is now, in this case, defined, right? And so also, if you want an array of something, which I should have probably put in the basics, but didn't think about until just now, but we did it anyway, it's great.
[00:03:41]
So now you can kinda have this thing where you can have a self-referential, recursive version of it as well. You just have to, yeah, if you don't have the value just yet, wait a second, and then JavaScript will figure it all out. Let's take off that to do.
[00:03:55]
And it's gonna blow up on me, because I've got all those other describes, so I'm just gonna there's only five in this challenge, so that'll be great. Multi cursor is for the win. Great, I'm only running that previous test file, so that Zod exercise is advanced. All right, so that one passes, and we're good to go and again.
[00:04:21]
Just to make my point, cuz I think it's worth a while.
>> Steve Kinney: For the ones who are lazy, we can't do it for you, so then you do need to give a little bit of hint as well. And I'm trying to remember how to do it off the top of my head.
[00:04:49]
>> Steve Kinney: This point, you might need to know the type first. I will look it up a second. I've done it enough times before, but I'm now forgetting exactly how to do it off the top of my head. So we've got that one, and okay, so the other one that's kinda interesting is something where we might wanna preprocess the data a little bit first.
[00:05:09]
And so the challenge here, if I scroll up and look a little bit closer, is I want it to either be this object that I think makes a schema or like a JSON string that is also could be that object. Do you know what I mean? So either the object or the JSON representation of that object, right?
[00:05:34]
And I need to do some amount of pre-processing to try to like, if it's a string, try to turn it into an object and then validate it. So now what's really cool is you can, kinda like, save yourself the JSON parses, right? You can just put in the schema.
[00:05:49]
Now it'll either be the object or the string that represents the object. Either is fine, you will get the object at the end as you processed it, it will have the right type. You will save yourself a whole lot of other sadness. So let's take a look at how that might work.
[00:06:08]
So we've got the z dot pre-process, and that starts out with a function that's gonna take something right. In this case, we've got an input unknown, cuz I don't know what it is just yet, and I am kinda insisting right now that it is, I did this looking at my own notes, that starts and close, like that is an object.
[00:06:35]
I'm not sure that that's incredibly important. Cuz theoretically, this will throw if it wasn't valid JSON, and maybe I was just being a little over the top. We'll experiment that together. I've already gone off the script enough times and suffered, so we're gonna stick to the script, and then I'm gonna go off script.
[00:06:54]
It's gonna be great. So we've got the ability to pre process it, and then I wanna make sure that it is that thing that I think it is, right? So that I wanna say that it's like in this case, what is it? What am I expecting it to be?
[00:07:11]
Let me check my own test. Cool, should be an object with the type JSON, the data value 42, great.
>> Steve Kinney: So we'll say z.object and the type, I believe, yeah, type is literal, JSON, and the date is a value of a number and I got close my curly braces or regular, awesome.
[00:07:49]
And so basically, all I'm doing, I think I can get rid of this part, we'll find out together, is if it is a string, parse it as JSON first, right, and then go check the object itself. So now it'll kinda hopefully work for both, we'll find out together if I made a boo-boo.
[00:08:11]
>> Steve Kinney: Cool, didn't skip, so, yeah, we should be good.
>> Speaker 2: Your top describe has to do.
>> Steve Kinney: Where, I thought I got rid of that one? We're gonna find out. Did I add it back? Why did I do that? This is why you live code with all your friends.
[00:08:28]
So, which one is failing?
>> Steve Kinney: All right, yeah, an actual one that should be found because I didn't get to it yet, so you'll love to see that. I can have a prefix, that test seems like a little bit much. Let's find out if I could have, this whole time, not checked anything about the string.
[00:08:59]
So, I gotta at least checked that it is a string in this case. But I don't think I need to check for the curly braces cuz it will pass this phase, but I think that the scheme of validation afterwards will fail, or I did it for a reason.
[00:09:21]
Yeah, so you can just parse it first. So if it's a string, pass it, move it on through, and then we're gonna check the object that comes out the other end. The test that failed is apparently a previous version of me wanting to make a union where something could also start with the string prefix, which is probably why I made it more complicated as well.
[00:09:42]
So I'm trying to think if there are other fun ones that we need to look at. Yeah, so this is sometimes you need to do something asynchronous to figure out if it's valid, right? The example I came up with is if it was a form, you wanna be able to see if it's a valid username by checking to see that username is taken.
[00:10:07]
In this case, I will have just a silly little function that returns a promise cuz it's an async function that will tell me whether or not it's taken, right? But this could be hitting the API, something along those lines. When would you use this one? Most likely like form validation or maybe to see that like is that ID taken already?
[00:10:31]
Something where you need to confirm what's the source of truth, whether or not it's valid beforehand or anything asynchronous. Which theoretically, I guess you could also go fetch that data and then check it all yourself. But then again, now you have the schema. It will go check the thing.
[00:10:47]
You will be happy. Life will be great. So in this case, what we can do is we can go and of just use refine to kinda get a sense of whether or not it works. So what we'll do is first we do need to make sure it's a string, right?
[00:11:06]
That seems totally fair. And so we'll say z.string, and then we'll refine with a asynchronous function to make sure that that username is not taken. Again, this would call an API. I did not set this up, an entire server for this as well. Let's make sure that passes, great.
[00:11:29]
And so now you can do asynchronous things. You can validate. Most useful thing there is the parts where you might do form validation or someone's lines, but I could come up, I could definitely riff on different places I would use in the server side as well. All the places that I have used it are very, very bespoke and weird, not worth talking about.
[00:11:49]
But it comes up. You can look at some of the errors I kinda in the name of brevity. The one that I also wanna get to is the one I talked to in the beginning, which is again, the answers are hiding in plain sight. But the ability to use this coerce first, which is to say, if this case, now, if it's anything that can coerce into a number, it'll be valid.
[00:12:14]
So, the number 100 will be, or just as valid as the string 100, right? Because query params are always strings, even in the browser or in Express. And lot of times, you'd be then casting them. And you're kinda a lot of times hoping for the best when you put a plus sign in front of the string and just hope it turns into a number, or, a parse int, and hope for the best, hope it's not NaN, which will technically be a type of number, so on and so forth.
[00:12:43]
So like, in this case, it'll allow you to say again, 01, will coerce into true and false. If you're looking for a Boolean, like a string that matches the number, it does all this stuff where it's like, sure, close enough. But, as long as it can become the thing, and the nice part is you will get the, the number out.
[00:13:03]
In this case, you'll get the Boolean. It will fix everything. And this can work the other way. If you say z.coerce.string, and you pass in the number two, it'll pass, and you'll get the string too, right? So a nice little convenience method as well. Cool, as you can see, it doesn't throw on a string 150.
[00:13:26]
It does in this case throw on 50 cuz that's less than 100. So you kinda got a whole bunch of stuff for free in one very simple line of code and again it will throw if you give it a b and c. So numbers that are number-ish, and you can validate it based on his number-ishness, that's a technical term, we'll pass.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops