Fullstack TypeScript, v2 (feat. Zod)

Zod Exercise: Fundamentals

Steve Kinney
Temporal
Fullstack TypeScript, v2 (feat. Zod)

Lesson Description

The "Zod Exercise: Fundamentals" 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 several schema validation challenges. The solution to the first four challenges can be found in this lesson.

Preview
Close

Transcript from the "Zod Exercise: Fundamentals" Lesson

[00:00:00]
>> Steve Kinney: So let's do kind of a tour of what we've got going on here, which is we've got an application where most of our time today is gonna be spent in the client and the server folders. Spoiler alert, one's an express app and one's a react app is anything we're talking about specific to express or react per se, no, but it is kind of like, I felt like the lowest common denominator of things that like, even if you don't write react all day every day.

[00:00:29]
And again, we're not going to touch a lot of the react code or express all day every day, you've probably seen enough of it before to be at least somewhat familiar with it. We're not actually going to touch too much of the action framework code itself, but we are just gonna have some stuff in there to make it a little bit more real.

[00:00:45]
We've got a shared folder for stuff we wanna share between the two of them and then we have this like weird exercises folder that shouldn't be in this repo, but like making you download two repos felt rude so it's here. Which is where we're gonna start our life together in this exercises, Zod folder here, where there are a bunch of little exercises that definitely, right now, need some schemas, right?

[00:01:17]
And so what we'll do is try to get our hands dirty like, listening to me talk about schemas any longer seems egregiously terrible. So why don't even if we're feeling like, but I just learned about this, I'm not ready to, we can do it. I believe in you, also the answers are like, right over here, and I will go after like, I will do it along with you in a second as well.

[00:01:38]
But like, you're not, you are in a safe space to start playing around, getting your hands dirty but what we wanna do is we want to take away the .todo here, right? And we're gonna do good old fashioned, test driven development, where it will be a sea of red, and we will seek to make it green and we will get a sense of that as we go along as well.

[00:02:01]
So from the main repo, like I said before, there's a few, like, little kind of sub folders between our client side app that we'll play around with, our server side app, some shared folder, and this weird little exercise folder. So what we'll do is we'll head in, you know, from the top I'll go into this exercises, and then in there, I've got this Zod set of exercises, and out of the box, if we just do NPM test, not a lot happens in this case, right?

[00:02:34]
We've got some passing ones, but the ones that we really want are skip to this point up. Pro tip, if you only wanna run one file, you can kind of type in some of the name of it, so we can do exercises.test. So right now, they're all skipped, which is intentional, they are called .todo.

[00:02:57]
This is all the test, didn't blow up because we haven't done anything yet. So you can remove that, I put some little mini ones in here, just to kind of like, slow myself down, you can do that, you cannot do that it's up to you, but we'll kind of get each one running one at a time.

[00:03:14]
So like I said, by definition, this is going to fail because one is not a zod schema at all. And typescript has nothing to say about it because you said that it's, I said, we said, it was said that we're gonna mark it as any, so this code will legit blow up, right?

[00:03:34]
And in our test suite, any blow up technically counts as a test failure, so going ahead, I can kind of take this first sweet here and I'll remove the .todo, and we can see it has blown up out of the box, right? There are some that are expected to blow up, right, so we'll play that game in a second.

[00:04:04]
>> Steve Kinney: So basically, we wanna see is our basic schema should have, should be able to kind of work with a type that has a name as a string and age is nothing but a number, but that number should be at least a positive number, like you cannot be negative five years old.

[00:04:22]
You can act like it, but you probably can't be it, so let's write our first odd schema together, which is, again, we know this could be an object. And in this case, we can say, yeah, name is a string and the age we can do, we have a few options I'll show you a bunch.

[00:04:42]
Let's make sure this passes first, okay, it passes so we can say number, and we get a little bit more granularity than TypeScript would normally give us, because like in TypeScript, there is a type four number. That number could be a negative number, a positive number, it could be 3.67, right?

[00:05:00]
So Zod does give us the ability to put some additional checks on top of that. So in this case, we can say it's a number, it should be a whole number, an integer, and it should be positive, right? Another way that you could do it, you could say something like, mean is zero so that will at least get you to the positive number right again.

[00:05:22]
It all depends like, do you insist that the age is an integer or not, right? I don't, personally, if I'm going with the assignment as given, like, this technically fits the assignment, but you could also do the INT. Yeah, and these are kind of just, as you can kind of see like refinements on that initial number so as we can see, they all pass, and just to kind of show you, I could say like type user z.infer, and this is that utility type, I can say type of,
>> Steve Kinney: And so now if I look at this type, you can see that I did a pretty good job of coming up with the Typescript type out of the box.

[00:06:05]
All right, so our first initial, we wrote our first odd schema, we're killing it, we're doing great. Awesome and so these all pass we can go down to the next one. Okay, so for my next one, I want to have an optional number, right? Okay, so let's go ahead and get these failing, and we'll look at two different ways we can go about this, so we can go ahead and again, we know it's gonna be an object.

[00:06:34]
And we know the names can be a string, so a few things you can do here. That's a little more than I wanted for the first pass in this case, but I like it and we're going to talk about it anyway. So we're gonna say that name is a string, number is again a positive integer, In this case, we can also say that it's optional, right?

[00:06:57]
And that if it doesn't exist, we do want a default value to it, which is nice so it's like if that is not on there, maybe zero is a fine answer, now the big question is like the logic of whatever you're trying to implement that is either the behavior you want or not the behavior.

[00:07:14]
My job is just to show you that it's an option and that you can do these kinds of things, we do have a failing test, let's see which one fails.
>> Steve Kinney: Interesting I have, you know, I'll show you the one that I did earlier, too, right? Because this is like the auto complete one but this one we did not get the default is zero, I'm curious it has to do with the chain, or what I have number min optional, default.

[00:07:44]
Number, min, optional, default, all right, let's put it back in the middle there, or the transform works too. Hey, hey we learned all, we all learned something together, which is the order matters. Cool, so now not only did we achieve the core part of having optional values in there, we also learned a little bit about the ordering along the way.

[00:08:11]
Cool, and so it goes through, and it does all these things, third challenge, this is one where we can reference other ones as well. One thing I do wanna show real quick is again, I think I deleted that other type so we can see again what the type is in this case, which you'll notice that it does say that there is an age property because we fill it in with a default, right?

[00:08:36]
If I got rid of this.
>> Steve Kinney: You can see that now it is actually an optional prop in the type that was created as well, right? Because whatever gets parsed, when you have a default value, you would have always got a number, so now TypeScript is not gonna yell at you about like, are you sure this number is possibly undefined and you're like, no, because I made a zero or an object or whatever, so.

[00:08:58]
When doing this, would you create your types in just that way? It depends, sometimes I already have the types, right? And so which way, I have to go the other direction if I don't have the types, and yes, right? But sometimes, it's like the types were for like, when we're gonna look at like, either open API slash swagger docs for like, that will generate an API like schema for you.

[00:09:23]
Like, in some of those cases, you might have the types from somewhere else, or you might have, especially if you're sending it to like, if you have the types of like, a third party API or an SDK, or something along those lines. You might have the types, but not the schemas, if you don't have either, then this will work, because, again, like you know, and you can write tests against it, right?

[00:09:41]
Are there ways to test types in like, various testing frameworks, like V test? Yes, does anyone do them? No, do we more likely test regular JavaScript? Absolutely, so it depends is the answer? [LAUGH] unfortunately, which is the answer for a lot of things, so awesome, so yeah, then like having ones that refer to other schemas like we kind of talked about before.

[00:10:07]
So we can go ahead and I kind of have at least the end state that I'm looking for, which is a person will have a name and then they will have some array of addresses, right? And Typescripts or Typescripts types are nice 'cause they are at all just kind of hoisted and stuff along those lines.

[00:10:28]
You do have to follow the rules of JavaScript when writing JavaScript, which is order matters, right? You can't reference stuff until it's defined, there are ways to do it we'll talk about it, but we're not there yet. So an address schema seems to have a city street, zip, apartment number that's optional.

[00:10:48]
So we can kind of play with some various options here as well, so we've got this object street part is easy, the city part is easy. As you can see, you can say as a string with a length of 5 you can then also provide a reject to make sure that it's like 5 numbers, right as well.

[00:11:10]
Which is nice because like you can't really do that in typescriopt? You can say it should be 5 numbers for those numbers could be lots and lots of digits, so like to say five actual digits is kinda nice as well. And here we wanna say that it's optional, and again you will get a type but the nice part is one schema can very very very easily reference another schema.

[00:11:34]
So in this case, we can say that a user profile is a object, and it's gonna have the name, that's a string and then an array, but you can see, I'm just referencing the one address. I could just literally say that address was, like, legit just point to the schema and like, those nested objects will all just work, right?

[00:11:55]
So if you find yourself, you can reuse stuff, you can kind of compose one thing out of another, so on and so forth, right? And so we go through, we make sure it doesn't throw as we validate the things, so on and so forth. If we add one where it's that, like too many numbers in it, or in this case too many obviously it will fail, so on and so forth.

[00:12:19]
Cool, moving on to this idea of like a union and so in this case, right, like we want to either the string literal anonymous or an ID and a name, right? And so in this case, we could make this one thing or not it's up to us. I'm actually gonna break it up into two just to make my point, anonymous schema.

[00:12:47]
This way it could be a literal so it's like we're not saying that it's a string or an object, we're saying it is literally the word anonymous. Or one of these other objects, I can make that anonymous schema as well and then for the user identity, I can do something like, actually, let's do a user schema as well and a different way of doing this is the answers but I've decided I hate myself and that I'm going to live code.

[00:13:13]
And be a cowboy about this, so here we'll say that the ID is a number and the name is a string, and so what we could do in this case is literally say that this is a union between those two, right. And again, I've got to make sure I delete these so they don't conflict, but I think I'm good.

[00:13:33]
Now, if we look at this, it is either, that's user schema. I want user identity schema so it's either the string anonymous or the things I'm expecting it to be.

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