Learn Zod In 30 Minutes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Zod is absolutely exploding in popularity and for good reason it's an incredible validation library and as you can see by the massive list of notes that's been scrolling over here we have a ton of content that we're going to cover because I want to simplify Zod for you [Music] welcome back to web dev simplified my name is Kyle and my job is to simplify the web for you so you can start building your dream project sooner and to get started I want to talk about exactly what Zod is now if you want a more in-depth explanation of what Zod is I have a full video cover now I'll link in the cards and description for you but the short version is is Zod is a typescript first schema validation Library the real thing about that that's really useful is it has validation built in and it has Type safety built in which are two incredible things if we go down to the introduction section we can see a little bit more about what makes sod so useful and really some of the biggest things are that it has zero dependencies and it's a very small Library so that's great because you can add it in without worrying about bloating your application it is immutable first which is great and it works really really well in a functional style approach it works in pretty much anywhere you can think of like node.js bun and so on and best of all it has really really good support for typescript but you can use it in just plain JavaScript if you want to but honestly you should be using typescript if you're working with Zod now with that out of the way let's jump into actually how we can start going about and implementing Zod to get started I just have a really simple Veet project just so we can use typescript that's all it's for you really don't need to know anything about Veet all we have it there for is for the typescript purposes the first thing we need to do is install Zod and it's super easy to do all we need to do is just type in npmi Zod and that'll install Zod for you it's super simple as you can see it downloaded incredibly quickly then in order to use that we just need to import it and we import this object called Z from Zod and this Z object does everything you need to do with sod you don't have to really worry about anything else this 1z object has everything about it built in now the only other thing that you need to worry about is you need to make sure if we go over to our typescript config that you have strict set to True inside your compiler options that's the only other requirement you need if you're using typescript with Zod but 99 of the time if you're using typescript that's probably going to be set so with that done we can actually start using sod and before I dive into all of the Nitty Gritty details I want to just show you a really quick example of Zod to kind of give you an idea of what it is and how it works so what I'm going to do is I'm I'm going to create a schema for a user so I'm going to call this user schema you can call whatever you want I'm going to set it to Z dot object so you can Define different things like objects strings booleans and so on so I'm going to Define an object that has a name property here let's actually make it a username and this username is going to be a string so we're going to say Z dot string just like that so I've created a user that has a single property called username which is a string and now what I can do is I can just say const user is equal to we'll create a user with a username like WDS we're going to give it a valid thing and then I can just console.log my schema and I want to parse my user and this just says hey does this user match the schema I've defined and if you look over here you can see it just Returns the user back to us which is good because that means it passed the validation if my username is for example a number instead of a string you can see we immediately get an error uncut Zod error that's great because now we can actually get errors based on our different validation if things are correct or not now another really great thing about Zod which makes it so much better than all most any other validation Library out there is the way it integrates with typescript normally if you had a type you would need to Define your user type and you would say you know it has a username which is a string something like that and then we would Define our user down here as a user just like that and of course we're going to get an error because this should be a string this is how you would normally do this and we make sure this says equal there this is how you would normally go about doing this is fine but you're defining your user schema twice so you're defining it here and you're defining it here the exact same data twice but was odd we don't need to do that instead what we can do is we can say our type user is going to be equal to Z dot infer and here we're just going to pass it the type of our user schema and that right there is going to take care of everything for us we can get rid of this type right here and we just got to make sure that we pass this as angle brackets up there we go so now our user if we hover over this you can see it is a type that is a username with a string so it automatically inferred the type for US based on our schema and as we change our schema and do different things to it this type for our users automatically going to be inferred this actual infer method right here is incredible and my favorite thing about Zod now the final thing that I want to cover before we start diving into the nitty-gritty is what happens you know if you have an error if we just remove this type here and we save you can see we get an error thrown to us so if we have add validation it throws an error to us but sometimes you just want to Boolean true false whether or not this is correct well in that case we can use a safe parse function and what that's going to do is it's going to return to us an object which has a success field which will be true or false and then it's going to return to us an error if the success is false or if it successfully goes along you'll see it returns to us the data and that data is just our object itself so the safe Parts allows you to actually do some true false validation which is really important if you want to do this for like a form validation instead of doing some database validation for example so that right there it covers all the basics you need to know so now let's dive into the nitty-gritty with all the different primitive types that sod supports so we already have covered strings we also have a number so we can do like Z DOT number for our age for example we also have things like a big end so instead of number I could do big int if this is going to be a big integer but in our case the number works perfectly fine we also have dates so I could say like birthday is going to be a z dot date and now we know that that's going to be a date we also have Boolean so I can say like is programmer Z dot Boolean just like that now this covers all the standard primitive types and if we come in here we just say that the user we want to get the success from this so we can just say that success you can see it's currently returning false because we haven't defined an age birthday or is programmer and that's because inside of Zod every single validation is going to be required by default so our string is required our numbers required our date is required our Boolean is required if you want to make them optional you need to add a DOT optional onto the end of it so if we did that and we added that to our number date and Boolean you can now see we are successfully passing because these three fields which we did not Define are optional while without that obviously we get a false a failure here now a few other kind of primitive types that I want to talk about are going to be things like undefined or any or never so if we just come in here we'll just do a simple test we can say Z dot undefined and this is saying that this value should always be undefined which is an important validation to look for we also have null to make sure something is null or we have void which again accepts undefined it's essentially saying there is nothing so like the return type of a function for example may be void now if you want to accept anything you could use the any type or you could use the unknown type both of these are going to accept any type of input at all and then finally if you want a key to never be defined we can just use the never type and that's essentially saying that it can never have this test key at all and if it does it will fail so that's all the different kind of basic types that we have but now I want to talk about how we can do validation Beyond just checking if something exists and if it's the right type because that's super simple and you can already do that with typescript so pretty much every single type inside of Zod will have different types of validations you can apply we've already talked about the optional validation which is available on pretty much any type but things like strings have a lot of additional validations and you can see that if we do something like Min we can Define the minimum length so we can say the minimum here is going to be three and now it must be at least three characters long and if we just make sure this person has like an age of 20 here we'll just do birthday whoops birthday is going to be new date just so we have everything working in is programmer is going to be true there we go so now it's passing it says it's true if we change this to be a minimum of five for our username our username is only three characters long we're going to get an error because it is not long enough we can do the same thing with like Max and so on I'm not going to cover all the different validations but you have tons of them like you can check to make sure it's an email or make sure it's a URL there's tons of them out there and pretty much anything you can think of for a string or a number is going to be there for example I can make it so that this is going to be greater than zero because obviously we don't want to have someone that's less than you know one year old so we can say like negative one that's going to give us a failure while one is going to be true because it's greater than zero same thing with date same thing with one you can do different things now some types of validations that are available on pretty much everything that I want to talk about we have optional which is saying it doesn't need to be there we also have nullable which essentially means that it can be the value of null so right now everything's passing if I change this to null you can see it still passing and that's because I have this nullable here if I remove this you can see it now shows up as false now there's another type which is a little bit confusing which is called knowledge and the difference between nullable and knowledge is nullish allows you to use undefined and null while nullable the previous one only allows you to define null so here if we put this as undefined you can see it shows up as false well if we have this as knowledge you can see that returns true because this works for both null and undefined while nullable only works for null so it's a little bit confusing but hopefully it makes sense now another really cool thing that we can do is we can actually Define default values so let's say I come in here and I say that I want the default to programmer to be let's say true so if I don't Define is programmer you can see we are still successful and that's because it's falling back to this default value here and that's where the actual return value from our parsing is important so let's just do a normal parse because it's a little bit easier it'll always return an object or an error and if we save you can see if we inspect our user here this is programmer field is set to true if I move my camera out of the way you can see is programmer right here is set to true that's because it's defaulting to that True Value so if you want to build the default different things using the default values is super important and really great you can even pass a function to default so for example up here we could say default is just going to be math dot random let's get rid of that validation right here that's just going to return to us a random number if there's no age so if we give this a save and make sure we Define our is programmer again there we go you can see that our age right here is just a random number and every single time we save we're going to get a new random number because it's calling that function for us we can also Define something called a literal so if we come in here and say literal we just need to give it a value in our case we'll say true and now it always needs to be this exact value of true so right now it's working you can see it returns to us our object but if we pass false for is programmer you can see false is not true obviously so it's going to return to us an error instead now another thing that's really common is let's say you want to make sure you have a list of values so I'm going to change this back to Boolean like we had it before now I want to specify some hobbies and I want this to be a list of values it can be like one of multiple different values but it doesn't matter what it is in that case using an e num is really important so we're going to say hobby here because we're only going to have one Hobby and we're going to Define this as a z dot enum so you just say Z enum and then you pass it an array of all the different possible values and now this can be one of a value of programming weightlifting or guitar but nothing else is a valid value for that so if I come in here and I say that the hobby is programming if I save you can see it returns just fine no errors at all if I change this to be something that's not in the list obviously we're going to get an error and that's really really useful and the best part is if we look at this user type here you can see when we look at that hobby type it has those three enum values listed so all of our types are perfectly matching up in typescript to what we've defined inside of our schema here now if you already have an enum defined using typescript you can use that as well but Zod pretty much always recommends using the Z dot enum instead just because it has better support but what you can do is if you did have an enum and this enum is going to be hobbies for example I'm just going to copy over this enum so I don't have to write it all out again let me just copy this real quick there we go so we have programming weightlifting and we have guitar and make sure this is an enum there we go so now what we can do is we can just take that obvious enum and here instead of doing Z dot enum we need to do Z dot native enum and just pass it in those hobbies and again if we look at our user type it has that Hobbies type right there and if we make sure we pass it something that was in that list you can see oops sorry needs to be Hobbies dot programming just like that you can see now it is working just fine and you can see that it's using numbers for the you know things I could come in here and change this to a string if I wanted to and now it's going to show up as that string programming it's just how typescript does the different enums essentially now another important thing to note about enums let me just back this up quite a ways to where we have the actual enum itself as you can see right here let's say I took this and I put it in an array just like that and now I wanted to use that array down here by saying Hobbies let me just make sure that's cleared out there and I'll make sure this is one of the Hobbies so it should work now if I save it looks like things are working but we have some typescript errors right here and the reason for that is because this Hobby's array could change and Zod doesn't know that it could change it doesn't know what the types could be and it knows that it could change so you need to just specify as const at the end here that essentially makes it a read-only array if we hover over this obvious you can see it is now read only which means Zod knows that this Hobbies array cannot change for example I cannot do hobbies.push2 onto the end of it it's going to give me an error because it's read only and that allows you to use that as an enum so if you want to Define your arrays out here just add as const to the end that way Zod knows how to make sure this works now that's a lot of the basic stuff then we can move on to talking about the actual object type because the object type is really core to doing any type of schema since you're mostly working with objects and has a lot of really cool things you can do with it so instead of trying to parse an individual user here let's just do user schema and we're going to use a few different message here methods here the first is our shape for example the shape just tells us what everything is so we can say like shape dot age and that is going to give me the exact Zod for that thing so it's going to give me all the definitions for this age property or I could do something like you know username and I'm getting all the different properties for the username you can see here we have our string and so on another thing that we can do which is really really useful in common is we can do a partial this works just like typescript partials and what this does is it just makes everything optional so if we just come in here I'm just going to get rid of you know that hobby which is normally required by default let's just get rid of a bunch of these normally all those things are required but we're doing a partial so if we just do our parse here on our user you can see it still returns our user just fine because we're saying all of the fields are optional this parcel matching is really great when you have like a multi-step form or just anywhere in a form where you have a partial user that you want to be able to check and that works just like typescript partial if we come in here and we make sure that let's just add the partial to the end of our schema up here if we look at our user type you can see that it is just making everything optional which is what partial would do inside a typescript we can also use things that are also in typescript such as pick and that allows us to just pick certain things so in our case we're going to say the username is in there and now if we save you can see our user type is just a username because we're only selecting the username same thing with emit we can omit certain keys so let's emit the age for example and now if we look at our user type here it has everything except for the age again that works just to like typescripts pick and omit also on top of partial we have something called deep partial deep partial works just like a partial but it makes sure that it goes nested down so if you have objects nested in objects nested in objects it'll make all of them partial instead of just the root object another thing you can do is you can extend an object so I can come in here and I can say you know what I want to extend this by adding something else I'm going to add on a name property which is a string just like that and now if we look at our user here you can see it has everything including a name at the end which is a string so we're just adding things onto the end of our object and if we had multiple schemas we could just do a merge and then we could pass in another schema in our case let's do Z dot object and we're going to do name is z dot string just like that so now we're merging these two different objects together and our user type is exactly the same it has that name String added to the end of it now the final thing I want to talk about if we just remove everything that we have I'm just going to go back to what we had with just the username because that's going to be super simple for us if I save you can see it's working just fine what happens if I Define a key that is not a username so let's just say name is Kyle if I save you'll notice the return from my parse gets rid of that key that's the default Behavior it removes all of the keys that aren't defined in your schema but if you want those keys you can just come in here and say pass through and that is going to make it so all the additional Keys like name as you can see are going to be passed through we can also say that this is going to be strict and in that case if we have a key that is not defined in our schema it's going to throw an error in our case we have this name key so it's throwing an error if we remove that now it's working just fine now that right there is everything you need to know about the actual object type inside again it's one of the more complicated types there's so much you can do with it but that's because it's obviously incredibly useful and you're going to use it everywhere now another type that we have is going to be an array let's say that we want to have an array of friends so we can come in here we can say we're going to have a z dot array and then we need to define the type of the elements in that array which in our case are just going to be strings so we can say here friends is going to be an array and it's going to have Kyle and it's going to have Julie sure now if I save you can see it's passing everything through and you can see we have our friends array just like that now if you wanted to get the actual schema of the element you would just say what's coming down here we have our user schema we want to get the shape of that as we've done before we're going to get the friends and now once we have that we can call elements or element I'm sorry and that is going to return to us the type of our array which in our case you can see is just a string I can hover over that you can see it is a Zod string so that's really useful if you need to get the schema for different things inside your array also we can make sure the array can't be empty so we can say non-empty and now for example our array is empty it's going to throw an error while without that obviously it works just fine also we can specify things like a minimum a maximum or even a hard coded length and that right there covers all of the more basic types we're going to run into so I want to cover some of the more advanced types as well and one of the first Advanced types you're going to run into is a tuple a tuple is very similar to an array but it is a fixed link link the ray where each element in the array has a specific type this is really useful for things like coordinates let's come in here we're going to say chords and the coordinates are going to be like an x a y and a z and they're going to be in the form of an array so we're going to say Z dot Tuple and we're passing in Array we're saying the first value in this array is a number the second value is going to be a number and the third value in this array is going to be a number this is a three coordinate system essentially so now I can come in here I can say chords I can say one two three and you can see my user pass is fine but if I make one of these a string for example it's getting an error because it expects each one of these to be a number now let's say this second one I want it to be a string now what I need to do is just make this second element in that array of string and it'll work but if I changed it to something that's not a string obviously we're going to get an error another really nice thing about this is you can chain all these together let's say I want this to be greater than four if I say if you see we get an error because our third value is three it needs to be greater than four so let's change it to five also I could say like for example it needs to be an integer and that's going to make sure it doesn't have a decimal point in the end now the final important thing you need to know about a tuple let's say that we have a tuple which has a string and it's going to have a date and then let's say it's going to have an infinite number of numbers that you can put on the end well we can use this rest property to just say anything else that we add on needs to be this type in our case a number so that is going to be how we do that and we need to make sure that this rest goes at the end of our Tuple just like that so now we've defined our Tuple we know the first value here needs to be a string then we need to have a date you can see that's working fine and if we want to add anything else as many as we want it doesn't matter they just need to be numbers and you can see it works but if I make any of them not a number obviously we get an error now oftentimes you may run into a type where you're going to have multiple values that can be for that type let's say we have an ID and the ID could be like a uuid string or it could be a number well in order to Define that with Zod we can use a union type so we can say that this is going to be one of many types so we pass it an array saying it can be a string or it can be a number let's just get rid of all these other types because we don't really care about them for now and I can just say the ID is a number two that works fine make it string that also works just fine and instead of using this Union syntax you could instead say Z dot string or Z DOT number that is going to work just fine as well as you can see we get the exact same results this is really useful when you're dealing with arrays for example now another type of Union that I want to talk about is going to be a discriminated Union I'm going to copy the code in for it because it's pretty long but it's a little bit simpler than it looks for what it actually does so a discriminated Union is essentially when you want to have a union where one field is exactly the same between all of your different things so in our case we have this object and it has a status field that is always going to be in every single one as you can see every single one of our unions has this status if we have a status of success the exact text success then we're going to have a data well if we have a literal that has failed then we're going to have an error and this is actually how these odd safe parse works because it always returns to us an object that has a status property of either success or fail and it's going to return data with a success and it's going to return an error with that failure for example if I change this to Safe parse you can see we get a success that says false and we have our error while if this was successful in returning what we expected this to be for example this said like status true or sorry success and data which is a string let's just return that for example you can see that it returns status of true or success of true and then it has our data at the end which is just you know our object can be returned to us so this is really useful if you wanted to do this and the reason you would want to Define your union like this because you could obviously Define your union the other way is this is just going to have better performance gains so if you are really worried about performance use the discriminated Union when you actually can now another thing that you may run into is what happens when you have like a map of users where you're storing things like this where you have an ID which is just like a string like this and then you're returning you know like let's just say you're returning their name at the end here and you know that you're going to do this for all of your different users but you don't know what the ID of every user is but you know you're going to have an object which has IDs of users and then their names afterwards to Define that using zot is actually really easy to have types for that so I'm going to come in here we're going to say like user math is going to be our type and we're going to use something called Z dot record a z dot record takes in what we expect the value to be so for example we can say Z Dot string is going to be our value so now no matter what the key is it really doesn't matter as long as we have an object that has a string only as the values this is going to work just fine so let's just get rid of some code here that we don't need we can get rid of that take our user map down here and let's just say our user here is going to have a key literally this key doesn't matter but we're going to have a string right here same thing here this key doesn't matter but we have a string you can see if I make sure I remove this and say if we have a success of true I'm going to just change this back to parse you can see it's returning our value just fine as soon as one of our values becomes a number or any non-string value obviously we're getting an error now if you wanted to define the keys as well you can do that so we can say our key is going to be a string and let's say that our value here is going to be a number so if you define two things the first one is the key second one is the value so if I change these here to numbers you can see this works fine because these keys are strings and these values are numbers just like we would expect now if I wanted to change this to be like a number for example that would throw an error or if I change this to a string obviously we're going to get an error but most often when you're dealing with things like this where you have set keys and you have set value types you're going to be wanting to use a map instead of a record and Zod has sport four Maps as well you just need to pass it the key and the value so for example we're going to have a string which is the ID of our user and we're going to have an object and this object here is going to have a name which is our user's name which is just going to be a string just like that so there we go now we have a user map and we always expect this to be a string and this value to be like the name so this would be like Kyle this would be John and this would be you know like ID John ID Kyle for example and now all we need to do is just make this an actual map so if you're unfamiliar with maps I have a full tutorial actually covering maps on this channel I'll link it up in the cards and description for you if you want but here we go we're just going to really quickly Define this as a map there we go and now let's make these commas and we save and I make sure that this is an object because that's the type I actually defined inside of my Zod schema this should return to us a True Result there we go so most often if you're going to be dealing with things like this you're going to use a map instead of a record but they are both available depending on your needs now speaking of maps another thing you can use is a set and a set is like a modified array where every value must be unique so for example if I just returned a set like this this user set if we just you know do a little log of it is going to just have one and two because it removes the duplicates and again I have a full video covering sets I'll link it in the cards and description for you we can use a set type and we can say for example got everything in this set must be a number and now you can see if we parse that out it's returning just fine as soon as I add a string we're going to get an error sets also contain things like Min and Max just like all the different array methods it works just like arrays but for a unique array when you're dealing with a set specifically now the final Advanced type I want to talk about is a promise actually you can actually Define a promise and Define what its return is going to be using Zod we'll just call this like promise schema let's create a new promise here const p is equal to promise dot resolve we're just going to resolve it with a string like that and we're going to validate this so we're going to have our promise schema we're going to parse that P value right there so now if we save you can see everything's returning just fine it's returning to us that promise if our promise resolved to a number for example you can see we're immediately getting an error or if we have something that's not a promise of course we're going to get an Erics it's not a promise so Zod validation for promises are a little bit unique because it has two steps of the validation the first step of validation is making sure the thing is a promise and then Zod comes in here real sneakily and adds its own little dot then and that dot then does the validation for this actual return type right here before returning it to you so that's kind of how Zod works with promises a little bit different because it's like a two-step validation as opposed to a one-step validation now the final thing that I want to talk about is doing some type of advanced validation and you can actually write your own custom validation using the refine method I'm just going to get rid of all the code that we have here I'm just going to copy this code over that we have and all this is doing is creating a string validate and we're using the refine method to refine our validation to add our own custom validation let's also validate this is an email sure because it is an email and all we're doing is we're just checking to make sure this email ends with at webdasimplified.com and if it doesn't we're just showing an email must end with webdevsimplified.com message so if we just say const email is equal to test at web dev simplified.com and we just console.log brand email dot parse of our email you can see it Returns the email just fine but if we try to do something else at the end you can see it's not working and it gives us a message email must end with at webdevsimplified.com Super useful you can also take this a step further by using a method called super refined which gives you really low level access to write your own custom validation hopefully most of the time you won't need this but if you need really low level access this is there for you and it just has extra methods and things you can do Beyond just the normal refine but for most cases this is going to work just fine now the very final thing I want to talk about is handling errors so let me just back this up to when we had a user that was easy to work with so we just go back quite a ways here where we had a full user schema because this will make work with our validations a little bit easier and I'll show you that validation inside of this kind of sucks a little bit so we have a username that's a string and we have our chord that works just fine now let's do our safe parse here and I want to just get our errors from this so if we look at this this is successful let's make it so our username is wrong in our case and we look down here at the error that we're getting and if we look at the error you can see it's massive there's tons of information inside of here like we have this errors array you know it's difficult to parse whereas our actual error message we have form errors you know we have our messages down here it's just really hard to parse everything that's going on inside of here because it gives you such detailed information about your errors so for the most part I don't recommend using this error object directly to form error messages instead there's a few things you can do number one you can write your own custom errors if you pass additional properties to all the different types you know like string Tuple and so on you can pass in things like an error map a description an invalid type error a required error so you can add messages in and same thing for like if I do different validations like dot Min I can you know Define the different message that I want so I can say like min length I'm sorry if we say three and then we can Define our message here like Min length must be three there we go so you can define a custom validation on the end of pretty much anything like that we can think of so if I just have this be like one value or two you can see here we have our code too small and hopefully somewhere along inside of here we have our actual error message that we can use which would be great as you can see midnight must be three but again this is clunky not always great which is why I recommend using a library to do this inside has a built-in library for this you can just npmi Zod validation error and this right here is going to give you really easy error messages with one single line of code so what we can do is we can import at the top here from that Zod validation error Library there's a single function that we want to import called from Zod air all that's going to do is it's going to take a Zod error and convert it into a method that's easy for us to understand so we're going to say const results is equal to this if results dot success is not true so if it's false then what we want to do is console.logout or from Zod error of our results dot error so we're just taking that giant error object right here we're passing it to this from Zod error method and now you can see it says validation error Min length must be three at username if we get rid of you know some of our default customization we change this back to number for example boom validation expected string receive number at username now it's not like the best user message to show to your user it's a little bit like programmatic but if you're creating like an API for example these error messages are really good and honestly they're good enough to show to a user they're going to see this and be like oh obviously that makes sense and that's all there is to Zod if you enjoyed this style of all in one video I have over 70 of them on the Channel with more coming all the time I'm going to link some of the most relevant ones right over here with that said thank you very much for watching and have a good day
Info
Channel: Web Dev Simplified
Views: 136,607
Rating: undefined out of 5
Keywords: webdevsimplified, zod, zod ts, zod js, zod typescript, zod javascript, zod tutorial, zod ts tutorial, zod js tutorial, zod javascript tutorial, zod typescript tutorial, zod.js, zod.ts, typescript validation library, javascript validation library, js validation, ts validation
Id: L6BE-U3oy80
Channel Id: undefined
Length: 31min 2sec (1862 seconds)
Published: Sat Dec 17 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.