Typescript & Zod tutorial with React-Hook-Form

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello and welcome I'm Dave today we will learn about a powerful new way to create your typescript types and validate your data at runtime and I'll provide links to all resources in the description below I'll also provide a link for you to join my Discord server where you can discuss web development with other students and you can ask questions that I can answer and receive help from other viewers too I look forward to seeing you there today we're learning about Zod now Zod in the Superman sense General Zod is a super villain but in the sense that we're learning about Zod Zod provides typescript for schema validation with static type inference so what does all of that mean of course it emphasizes typescript but a schema describes the structure of your data and that's kind of also what we do with typescript right but here's the difference typescript helps at the data type level during development your code is compiled of course after that and that leaves a blind spot right so what about the run time after the code is compiled well sometimes you can receive unexpected data that can come from a form with user data it can come from an API or even a database but Zod lets you apply runtime type checking so now you may be thinking that's great but now I have to define a schema and a type for the same data but that's not right because this last part here static type inference we can infer our types from our Zod schema and that's very awesome so let's check it out okay I've got Visual Studio code open and I'm going to move a little faster today because I'm assuming you already know typescript and you're interested in this and so instead of like typing along with me we're going to just review code overall but I do want to show you what you could install or you could of course download my code from the repository Linked In the description so to start a project like mine you would go ahead and open a terminal and from there let's go ahead and clear this out and then I'll redo some of what I showed installed there so we'll type npm create Veet at latest to create a react project after you get that you'll want to go ahead and go into the project folder that you just created with Veet then type npm install to install all of the dependencies and then finally after that you're going to just want to do npmi and Zod to install Zod now let's look at our example okay notice I've got an example.ts file and I've put it inside of a models folder because that's where I usually put my schemas when I model the data I'm representing the data that I'm working with here so the first thing we're going to do is import Zod and that's just import and then you destructure Z from Zod after that I'm going to create the most basic schema that I could possibly create here just for an example I've called it my schema and it is just a Zod string and this is required fired by default just like in typescript when we create a type unless we say it's optional it's required okay after that let's look at parsing this data so we call the parse method on the schema and here I'm parsing the string Dave and it's going to say it's Dave and it matches the schema it's a string and so we'll get Dave but if not if we pass in a number for example then it's going to throw this Zod error here now there's another way to parse as well we look at that this is called safe parsing and it doesn't throw an error if the validation fails instead you get an object so here in the object we would get success and that would be true and the data would be Dave and then if it's false of course we'd have success false and the error would be Zod error so you get an object if you're using safe parse and in an application you may actually want to use safe parse because then you can just handle that error how you want to here we would have to use a try catch and catch that error now of course there are many other things to Zod and this is a basic example but one I want to show here in this basic example is the use of coerce and we chain things when we Define our schema so we have Z dot coerce dot string usually everything would come after the data type here but coerce become or coerce comes before the data type and that's because it's coercing whatever data it receives to the data type so if you want to make sure you're receiving a string then you would use coerce in front of that then we can just use parse of course so now when I pass in Dave it would be the string Dave but also when I pass in 42 it would be a string of 42 and when I pass in a Boolean like true it would be a string that has that value and now I'm at the website for Json placeholder and I could put a link to this in the description as well but I'm just going to create a schema based on the user data here so the day data that we would expect to receive from this API so we can look at a more complex data type than that simple example okay we're back in vs code we're still in the models folder and I've created a user.ts file here for our user schemas and we're starting with a basic user schema you can see I've imported Zod at the top once again and now I'm defining this basic user schema and you can see it starts as an object just like that data type from Json placeholder so we start with a z dot object then inside this object we start to create all of the data types so we had a name and now we can chain the different requirements and you can look at the Zod documentation there's a lot of things there and I'm not going to cover everything today but I think this would give you a good start and here we're starting with it's a string data type and I'm also chaining a trim on here and that's because I'm also going to use this schema in a form that we'll get to later and so any user entered data there might have an extra space or something and I just want to trim that and then I'm also saying it has to have a minimum length of two and I'm providing a message here for validation and this will be displayed along with that form if the user doesn't meet this minimum so there you can put in a message for each data type very useful and that's very useful when you're validating forms and want to give your users some feedback so let's look at the next one username it's very similar but notice we want the username to always be lowercase so we're going ahead and chaining chaining to lower case on that as well we've got a minimum of four here with a message now here's our email notice Zod has its own email validation that we can chain in there as well so we're making sure it's a string we're making sure it meets the requirements of an email before we trim it and set it to lower case now here for the phone number I've commented a few lines out because of what I would personally do probably for a form versus what we need to do here just to match that API data that's going to come from Json placeholder so to match the Json placeholder API data we can say it's a string we can say it has a minimum of 10 characters or 10 digits but after that if I was working with a form possibly instead of just this minimum of 10 digits I would use a reg X here and make sure it just gets numbers that are 0 through 9 I would probably make sure there was a length of 10 and then here's something very powerful you can pass a function with this transform method that you can chain and here I would go ahead and slice up that string that I required to be a length of 10 and only numbers and I would put the dashes in between like I'm used to seeing here in the US I realize other phone numbers from other places may be different so you might want to do something different this is what I would do and I would slice it up and put the dashes with that appearance so you can transform the data as well notice here with the website I also commented this out but I just wanted to show that you could do this as well and we could apply this to a form for example because we wouldn't just get the string and trim it and set it to a lower case we would also make sure it meets the requirements of a URL as defined by Zod and then notice we're chaining optional here so any inputs we want to be optional we can chain that just like we can Define optional information in a typescript type now here's what I actually did for the website the data that we're getting from the API so we start with a string we go ahead and trim this into lower case and the trims more for the form again then we say a minimum of five characters we're not using that URL type at all because some of the data from that API doesn't meet what Zod defines as a URL however we are using this refine method and it's very powerful like transform notice I'm passing a function here and I'm just making sure there is at least a period in there so we could have a.com or dot IO or whatever at least there's something in there and we know it's a URL without that we're saying it's an invalid URL we're still making it optional as well and then there is a nested object here so notice company is another object and then inside that object we're putting a name and a catchphrase and if I remember right the API actually has one more property here as well and we're just ignoring that and you can do that as well so if you don't put it in your schema Zod will not go ahead and pass it on after it's parsed so you can filter out unneeded information that way here we have the name again string trim a minimum character message if it's not met and then a catchphrase that is optional and a string but notice we didn't have an address in this basic user schema at all so we're going to get to that as well but first let's use this basic user schema and I'm going to use it in this Library function for fetch users so let's look at this function I'm importing that basic user schema that we created in the user model and I'm bringing in Zod as well so now I expect to get user results and those user results will be an array from that Json placeholder API so I'm saying it's going to be a Zod array and I'm basing the users inside of that array off the basic user schema now here's the powerful part where we don't have to Define types as well we can infer using Zod dot infer so here's type user array and then I just use Z dot infer and say type of user results and now I can look at this user array type we can see it's the user schema we defined and it's an array type down here so that just created our type for us so now as I create this function it's either a user array type or it's undefined because we might return undefined if our response is not okay for example so as we get down into the function you can see we get our Json that is a user array type and then we parse that data and I'm just saying user results dot parse notice not safe parse here so we are catching an error if it occurs and we're parsing that user's Json and of course this is inferred because we already have the type up here and I'm just logging this to the console so we could see the result so if we look in our app.tsx here you can see I'm importing fetch users and we're calling this before the app functions so it is just called once and we should see the data logged to the console notice I am importing a form here but I've commented it out for now which is why we see the gold or yellow highlight here because typescript is saying we're not using the form yet but we'll get to that let's go ahead and start this project now so we open up a terminal and after that we can just type npm run Dev to start the Veet project and we'll go ahead and click on localhost 5174 I've pulled up the browser let's open the dev tool so we can see the console and we see in the console we have an array of 10 users so let's look at this user data and we can see we get the company that's even a nested object email name phone username and website but we don't get some of that other data that was in the data that is received actually from the API like the user ID or the address things like that so we kind of discarded that when we didn't put those inside of our schema so let's look at how we can optionally add some more of that to our schema I'm back in vs code in the user model file so let's scroll down underneath the schema we created and now let's look at creating an address schema that is separate because that address data from Json placeholder is also a nested object so we create that with an object and it has a street sweet City and zip code but there was one other piece that was added to the address as well and that was geo coordinates so we've got latitude and longitude here its own object so it's a nested object within the address object that is within the larger larger user object so we have to work with both of those let's look at how all of this works so here we Define our user address schema much like we did our basic user schema above you can see I'm applying a regex here as well to part of the zip code for the address and other than that it isn't anything that we didn't really cover before let's look at the user address schema with Geo down here notice we're extending the user address schema so we're going ahead and extending what we just defined above and then we're adding in this Geo part to it now here you would expect this latitude and longitude to possibly be numbers but if we look at the data from Json placeholder it's also string data so that's what's expected and if it doesn't match remember it won't validate so that's what we have set this to as well and then notice underneath this I've also defined a has ID schema and this is an object that has an ID that is a number because it is a number inside of that API data we're making sure it is a integer as well and not a decimal or anything like that we're also making sure it is a positive number and let's look at what we can do with this information so here we're defining a user schema with address so we're taking the basic user schema and then we're extending that schema and we're adding the address property to it and we're just applying this user address schema remember it doesn't have the geo coordinates and then we're going ahead and chaining at the end of that and we're merging that schema that is extended with the has ID schema so that will also be added so I wanted to show both ways you can do that we could extend and add this ID property this way the way we defined it or we could Define it up here and then we can just merge with it so we're just chaining that together likewise with the user schema with geodata we're using that basic user schema we're extending the address but now for the address we're using that user address schema with Geo and then we're once again merging in that ID so then we've essentially created two different ones here we've got a user schema with the address or we've got a user schema with the geo coordinates as well and once those are defined then we can infer the types from those schemas that we've created with Zod so we have a user with address type or a user with geo coordinates type okay now let's take these schemas and type types and go back to our fetch users where we can use the new ones so instead of basic user schema we'll have a I believe it was user address user schema with address there we go and I'm going to copy that down and put it here where we create our user results array as well and now we're going ahead and creating that array for user results it's the same and we're inferring the type of here is the same as well so we should be good with this user schema with address for our first example now let's go back to the browser and see what we get inside of the console here for the latest results so here's the latest results and now let's see if this has an address added and yes it does so besides the nested company object now we have a nested address object and you can see inside of the address we have City Street Suite and zip code we do not have the geo coordinates because we didn't add that so let's go ahead and do that next with the other type and schema that we created so once again inside of the fetch users let's say user schema with Geo and I'll just select both with control D arrow to the end back up over here say with Geo there we go save that and so now we've got user schema with Geo so now with these changes let's once again go back and look at the latest data in our console we scroll up we have another 10 users here and now let's look at the address and the address data should have this nested Geo data inside it as well so we've once again validated the data according to the schema and applied Zod and we did not get any errors notice this data is a string type that matches our schema but we did not coerce any of this data we made sure we were defining our schema according to the data the API told us we would receive before we move on to the Forum I just wanted to come back to the user schema for a little bit because if this looks complicated to you of course dive into that documentation you just want to learn what all of these things do and this is basically just working with objects here so you're extending an object by adding a new property to it or you can merge another object with a pre previous object like we did here with the has ID schema so there are both of those options and many more options available in Zod so you can see what all you can require and apply to these different data types just like I changed these different things here for each data type as well okay let's move on to working with the form and applying that Zod validation so I've got the terminal open I'm going to stop our application for now we're going to need to install react hook forms in a resolver so this is what you'll want npmi and then react Dash hook Dash form then you want a space and you also want at hook form slash resolvers and let's remove that ending part because you do not need that you just need at hook form slash resolvers you go ahead and enter that I've already got mine installed but let that install add that to your dependencies I'm also using Tailwind in this project and if you download my code and install you'll have it if not you can of course install Tailwind as you might already know how to do into your react project a quick look at what we're using we're using react hook form which is a very popular library for react forms this is react Dash hook Dash form.com and if you go to the get started page you see some examples and they do provide typescript examples that's very good but we're not going to use just the basic example here I wanted to go to the typescript page and right now the typescript page is not loading well and I haven't been able to get it so what I did is I I put this URL in Google or the URL for the typescript page which is just slash TS at the end I Googled it and then I pulled up the cached version so the last copy they have was about a week or so ago May 17th and then we get the typescript support page now I'm going to use code that comes from this submit Handler example and then I merged some of this code with the code I found found at the hook form slash resolvers dependency here for react hook form because this is where it supports Zod and they have different examples I went to the Zod example and applied much of what I saw here where we're going to use the Zod resolver as well so I'll put both of these links in the description but I wanted to show you this ahead of time we're also going to use the use form hook that is available from react hook forms and we'll apply this trigger here which is one of the many things that you see over here on the left that are available from the use form hook with react hook forms we're back in vs code and I have my form component pulled up I'm going to review this code with you instead of typing it out because it would take me much longer and I think you could slow this down or repeat anything you need and I've provided the code as well so what we get from react hook form when we import here is the submit Handler and the use form hook and then from the hook form resolvers slash Zod is where we import this from we import the Zod resolver after that I'm importing the user schema with address that we previously created in our user model and then I've also imported the type now user with address and we're going to apply all of this to the form so now when we start to define the form component we're going to get several things from the use form hook and we need to say hey this is a type user with address right here when we pull in the use form hook so we're going to pull in register handle submit trigger and then a form State and we can destructure errors from that form State now inside of this use form hook we have a resolver and this is where we use the Zod resolver and we pass the schema that we've created so the user schema with address that we imported from our user model if we scroll down we can create an on submit function here that is called when we submit the form and it's the type here submit Handler and this is where we pass the type user with address as well now here I'm just logging data to the console so we're just making sure we get that data you could do whatever you wanted here with the form you would probably send it somewhere else store it in a database whatever you would do at that point but just know that it is being validated before you get it here so we would have validated data to handle right here inside of the on submit function so let's look at the basic form before we pull it up in the browser and it starts with a fragment and that's because I have a button and then the form and this button uses the trigger function so I'm just calling it here in the click Handler and this trigger is going to display the data requirements so you're essentially triggering the form like you submitted it and then of course none of those requirements are met so it's going to display the data requirements underneath now if you you have more than one requirement as defined in your user schema it's going to give you one error at a time and as you fulfill one of those maybe the next requirement isn't fulfilled yet so it will display the error message for that if you have more than one and we can see how that works as we fill out the form so here's our form and the on submit click or the on submit Handler I should say receives this handle submit and then we just pass on submit to it now handle submit is just part of what I saw in the example code before we had here so we have this handle submit pulled in here it's nothing we defined it's just something that we get from that use form hook and then we pass our on submit function that is the submit Handler right here after that everything's going to be very much the same for every input for the most part so we start off with a label of course that's linked to the input and then we can display errors if they exist now there's a couple of things to note here react hook form has us using register which we also pulled in from use form up here here's register so notice here we're spreading register here and then putting in the name that we have for the input so we need to do that for each one of these and then if there is an error we can display the error so if an error exists here which is what we're checking before the double Ampersand then I have a paragraph that will have red text and a yellow background and it will display the error.name and message if it exists so notice we're just using optional chaining on the message and this applies to pretty much every field as we go down and it's a fairly long form because I wanted to have several examples and we're basically matching up all of that user data for the most part so you can see all of this code in the examples here and we even get down to company name company slogan and catchphrase all of these things are right here so now let's go ahead and look at the form and see how it works and for me to show the form I'm going to need to go to the app component that we have over here and go ahead and remove this comment so the form will actually display we were already importing it but I had it commented out so now that we have that let's open up a terminal once again and type npm run Dev if you remember I had previously stopped the dev environment from running because we installed everything else we needed for react hook forms as well let's go ahead and click localhost 5174 and we'll look at our form in the browser so here is the form and I've got this display data requirements button over here and then after that I've got the form centered and looking a little bit better but I wanted to add this button with the trigger function just to show what it could do but let's first let's fill out the form before we would just display the data requirements so I'll start typing my name go ahead and say Dave Dave just twice but notice we're not getting really any messages for validation and so we're not sure if what we're putting in is good or not so if we display the data requirements or if we go ahead and submit down here and we're not meeting any of those requirements we're going to get all of those validation messages it looks like it's okay with the username but what if we had something like yeah here it says username must be four or more characters long now that I deleted it and we could just put in Dave like that and then it goes away once again so here this is an invalid email we have to match all of that up so we would say email at email.com looks like it's good with that 555 Street we don't have to have a suite that was optional here's Kansas City that would work just fine we have five five five five five optional four-digit extension notice so we don't have to have the four digit extension but if we do or we start to add it we need to go ahead and complete it and then for a phone number here I've got the hyphens in the placeholder and I probably shouldn't but it would go ahead and allow it because I didn't put in my preferred regex I put in what would match that API data so here we could have just about anything I think say one one two three dash one two three four yep that's just fine and URLs must be at least five characters so if we said my website after that now it says invalid URL because we met the first requirement which was the minimum five characters but we didn't meet the URL requirement yet remember that at least had to have a DOT that we used in that refine function there and we could put an a company name and Acme Co seems like it's just fine company slogan is optional so we don't have to have that either so by doing all of that we could actually see that we fulfilled everything that was needed so if I refresh here then we clear all of that out essentially by refreshing we could have put a reset button here as well but we just cleared all of that out now if I just want to display the data requirements that calls that trigger function and it does the same thing and then notice if we try to submit it's really not going to submit we'll go ahead and open up our terminal over here we have our array of 10 users that we were getting from our fetch users but it's not submitting the data when we do submit it it will log to the console because it is not validating so now we can go ahead and say hey I can fill all this out again quickly hopefully at email.com55 Street AC is good we'll say zip code 55555 phone number one two three one two three one two three four website your website.com and Acme oh seems good let's submit and we're not getting anything in the console like expected and I think I know why we're going to need to go back to vs code so I'm going to pull that back up let's go ahead and close out of the terminal window and what we want to do here with form state is pull in something else from the use form and that is is valid and then from there we could just log that somewhere here in our component just to see if we are providing valid information to the form that matches our schema for example so now we can pull the browser back up of course we re-saved everything but we instantly have false so we know that's working so before I fill out the form once again let's go ahead and go back to the code because I know the problem and the problem is back here in the user that we defined in the model that's because we're not providing an ID but right now we're trying to use the schema that does have an ID with it so we have the user schema with address right here notice we're merging the has ID schema onto that and if we go to the form we're using that user schema with address so let's go back here to user find user schema with address and let's not merge that ID in for this example so I'll just comment that out and now we should be able to fill out our form and it would be valid so let's go ahead and check that out as well and you could display that valid if you wanted to but it wouldn't make much sense to the user this is something you definitely want to catch during development that your data schema matches the form that you're creating so now let's fill this out again and let's see what we get over here in the console after we fill it out so I'll do this as quickly as possible Dave hey Dave email.com55 Street hey c55555 and one two three one two three one two three four website.com acnico and now it says it's valid before we even submitted so the form is telling us hey yes it's valid so that's a great thing to check during development let's go ahead and submit now we get everything here inside that we were logging in that on submit function we were logging the name individually and then we were logging this information here we we got the is valid from the form a couple of times as well but this is what we really wanted to ensure that we got after we submitted the form because then we could work with this data send it to somewhere else or anything like that so just a good example right there of something I didn't check before I forgot to remove that ID when I was working with the form so I would want to actually probably create another schema that didn't have that ID and then one with the ID to use with the API for example so overall Zod is really helping validate that data and the types we're inferring the types from that Zod schema so everything is matching up from development right into runtime and I really like working with Zod and I think I will continue to use it in future projects remember to keep striving for Progress over Perfection and a little progress every day will go a very long way please give this video a like if it's helped you and thank you for watching and subscribing you're helping my channel grow have a great day and let's write more code together very soon
Info
Channel: Dave Gray
Views: 23,216
Rating: undefined out of 5
Keywords: typescript zod tutorial, typescript, ts, zod, zod validation, zod tutorial, tutorial, react-hook-form, typescript zod react-hook-form, type safety, runtime type checking, runtime type safety, data validation, form validation, typescript zod react, zod react, zod infer, zod schema, data schema, zod introduction, user schema, zod merge, zod extend, zod typescript, zod ts, zod data validation, react-hook-form zodresolver, zodresolver, useform, react-hook-form ts, typescript zod
Id: JZjUv_qFtvM
Channel Id: undefined
Length: 32min 30sec (1950 seconds)
Published: Fri May 26 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.