Best Practices and Advanced TypeScript Tips for React Developers

Recording available for Multipass and Full ticket holders
Please login if you have one.
Rate this content

Are you a React developer trying to get the most benefits from TypeScript? Then this is the workshop for you.

In this interactive workshop, we will start at the basics and examine the pros and cons of different ways you can declare React components using TypeScript. After that we will move to more advanced concepts where we will go beyond the strict setting of TypeScript. You will learn when to use types like any, unknown and never. We will explore the use of type predicates, guards and exhaustive checking. You will learn about the built-in mapped types as well as how to create your own new type map utilities. And we will start programming in the TypeScript type system using conditional types and type inferring.

158 min
09 Dec, 2022


Sign in or register to post your comment.

AI Generated Video Summary

This workshop covers various TypeScript and React-related topics, including TypeScript compilation and type checking, prop definitions, data validation, and type inference. It explores the use of generics, type mappings, and read-only types to ensure type safety. The workshop also highlights the importance of validating data at the boundary of the application and handling undefined values. It concludes with gratitude for attending and encourages further exploration of TypeScript and React.

1. Introduction to TypeScript Tips for React

Short description:

Welcome to this workshop on best practices in advanced TypeScript tips for React developers. I'm Maurice de Beyer, a freelance developer instructor and Microsoft MVP. Let's get started!

Good afternoon, everyone. Welcome to this workshop on best practices in advanced TypeScript tips for React developers. My name is Maurice de Beyer, also known as the Problem Solver. I do a lot of stuff. Amongst other things, I'm a Microsoft MVP for the community work I do. So workshops like this. I'm a freelance developer instructor. Currently I'm working for a Fintech startup in Amsterdam, called Someday. Based in the Netherlands, as you might have guessed from working in Amsterdam, although I used to travel quite a bit. Not so much since COVID anymore, but I still like to travel a bit. My website's here, my email. Website's not all that interesting. My email might be more useful to you. And my Twitter handle in case you want to send me messages.

2. Overview of Topics and Course

Short description:

In this workshop, we will cover various TypeScript and React-related topics, including dealing with props and React components, making TypeScript stricter, validating data, using TypeScript mappings, and bridging compile-time and runtime safety. I have also turned this workshop into a course on Udemy, which you can subscribe to for free using the coupon code Berlin-22. The course covers all the material we will cover today, but due to time constraints, we may not be able to cover everything. The course includes exercises for each topic, and I encourage you to type the code yourself to better remember it. Each module is independent, so you can skip exercises if needed.

Now what are we going to cover? Well, I'm going to cover a lot of TypeScript and React-related things. Some of the things are with React will be interesting if you use React with JavaScript. But that's really not my focus. My focus is using React with TypeScript. And quite a few of the tips I'm going to provide you with TypeScript are actually not specific to React. I'm using them in the React context. But most of those are equally applicable if you write TypeScript code in some other way. So even if you would use Angular or Vue or Svelte or something like that, or maybe some server-side code using Node.js, then most of the things will still be applicable. You just kind of have to translate it.

Some of the things we'll be looking at is how to deal with props and React components props and TypeScript. How to declare them, how to make them generic, for instance. Deriving types from existing components, using TypeScript inferring for things like that, and several tricks like that. Then we're going to take a look into making TypeScript strict or even stricter than normally, because I'm sure you've all heard of the strict option in the TS config, where you can set strict to true in TypeScript. It becomes a lot stricter, detects a lot more potential errors. Well, it turns out that you can go stricter than strict. Because turning strict turns on a whole bunch of additional checks, but it doesn't turn all the additional checks. There's some very interesting ones. Specifically, one I always recommend people enable is the no unchecked index access, which we'll be taking a look at. Then I'm going to do some validating of data, which is strictly speaking not TypeScript or React-specific. You could use that with JavaScript or anywhere if you want to. In fact, I recommend doing things like that. But there is a nice bridge to using it with TypeScript, where you can start inferring again, TypeScript types from the Zot Schemas. I'm going to do this with Zot, but this is not specific to Zot. In the past, for instance, use YUB and YUB has very similar capabilities. Zot is better in my regards, so that's why I prefer these days, but it's certainly not the only option. We're going to take a look at TypeScript mappings. Some of the standard mappings like omit, pick, read only, things like that, where you basically can take an existing TypeScript type and create a new TypeScript type based on the original one. With things like omit or pick, you can create a new type which is smaller or read only, you can create a type which has the same shape, but TypeScript won't allow you to make any changes. As the name suggests, read only says, you can read it, but you can't write to it. But we'll also create some custom type mappings where we'll expand on some of these concepts. For instance, one of the things I'm going to do is I'm going to expand read only which is not recursive, and I'm going to create that into a recursive read only, which is even more useful and relatively easy to make. Actually, quite a lot of these type mappings are surprisingly easy to make. Not all of them, the type mapping from a Zotsch scheme to a TypeScript type is hardly easy but lots of them are. And then in the end, I want to wrap up with looking at how we can bridge compile time safety where you get fast feedback as a developer with runtime type safety. Because type predicate and the assertion functions and exhaustiveness checking are a mechanism or different mechanisms you can use which will give you compile time checking which is nice for fast feedback but it will also give you runtime type checking. Because in general with TypeScript you get compile time type checking when you're developing the next runtime it's just JavaScript. So runtime your assumptions about your types don't actually work out. Then you might get a random error you might use undefined somewhere without realizing it. So this is actually a very nice capability.

Now you might be thinking that is a lot and we've got four hours and indeed it is a lot because I prepared a workshop like this. I always wanna show a lot. I think, oh I wanna show this and I wanna show that and I wanna show etc. And then I wanna talk about all the stuff I wanna show. And then I end up with way too much material. So what I did is I actually turned this workshop into a course as well and posted that to Udemy earlier this week actually. And I created a free coupon codes there's Berlin-22, as you can see on screen. And with that coupon code you can get the course for free. So it's basically all the material we're gonna cover today, except I already know in advance we're not gonna be able to cover all of it. So I'm just gonna go as far as I can. Subscribe to this course for free and you can get all the... First manager. If you don't care, fine it's really up to you. Because of the way Udemy is set up, I have to limit the amount of users a bit. They basically allow me to either create a coupon code for a hundred users, which is valid for a month or one for a thousand users, which is valid for only five days. Not knowing in advance how many people would be here, I created one for a hundred people which is valid for a month, which means with a number of attendees, that it's quite possible that they will run out. If that happens, just send me an e-mail or ping me on Twitter, and I'll create a new coupon codes for the next group of people. You'll still be able to get it. Now another thing about this workshop is we're going to do lots of exercises. Basically, I've got lots of subjects as you saw, and each of them is, I'm going to tell you about it, I'm going to demo it, and then you're going to try it. I'm going to provide you with all the code you need. If you want, you can copy and paste it. But if you copy and paste, you're not going to remember quite as much about it than if you actually try it. Well, if you need to copy and paste just to get things done, feel free to do it. But I recommend you type in the code, see errors that occur if you make a typo, and do it that way, because you will remember far more than just by copy and pasting. You don't need to worry about not being able to complete the course. Each module is basically set up separately. So it's not like, oh, I didn't complete exercise two. Now I can't do exercise three because it builds on top of it. They're all separate. So if you didn't complete two, you can just start with three in with a clean slate, no problems there.

3. Setting Up the Development Environment

Short description:

To get started, make sure you have a working machine with a relatively recent version of Node, npm version 7 or later, and optionally Git. You can check the versions using the terminal commands 'node --version', 'npm --version', and 'git --version'. The code for the workshop is on GitHub, and you can clone the repository or download a zip file. Once cloned, navigate to the project folder and run 'npm install' to install the dependencies. After that, switch to the '00-start' branch and start the application.

Now, we all need some prerequisite, a working machine. I'm kind of assuming that that's okay for everyone because this is kind of targeted, not at newbie developers, but the people who are already using React and maybe TypeScript to some degree. I'm not gonna cover the basics there. It's kind of assumed you know that, which kind of means you probably are covered here but you need to have a relatively recent version of note installed. I'm not sure if 16.17.1 is still the current version, probably not, but doesn't need to be quite as new, but at least relatively new. I think 14.something or later is fine. You need npm, version seven or later is gonna be fine. And having Git installed is beneficial, not strictly speaking required, but it will make life slightly easier if you do. But if you don't have that, that's fine. Now, if you want to check whether you have those, just go to terminal window and do notes, dash dash version. And that should give you a version, the same with npm, dash dash version. And that tells me I have a mon, 18.19.2, and I can do the same with Git. And that tells me I'm using Git 2.38.1 on a Windows machine, which I am. Especially with Git, it's just like you can do without Git, but if you have Git, any Git version is basically fine, and Git 1 doesn't really matter. We're only gonna use it to clone a repo and switch branches once. The code is on GitHub, so if you don't have Git, you can download a zip file instead. I'm gonna share a link to the slides in a moment, but if you wanna use or need to install anything, all of these images are, and that doesn't work. That opens up on my other window, my other terminal. So if you click on an image like that, you'll end up like here on the Node website where you can download it. Just in case you're wondering which version, Current is like the bleeding edge with all the latest version. LTS stands for long-term support. So in general, you want to use the long-term support version which is kind of recommended for most people as it says right here. There are the slides again, but I'm kind of assuming that this is gonna be fine. Also, if you wanna follow along, this link, that's the important one, slash react-ts-2022. If you click on that, it will open a copy of the slides and you can see here exactly the same slides with that link to the Udemy course and here the links to all the other stuff. It's also a link to the GitHub repository here that takes us to the GitHub repository which contains all the code we're gonna use. This is basically a Next.js application. And if we look in the Pages folder, you can see there are a whole bunch of different pages with all the different steps we're gonna do in the exercises. I'll come back to this in a moment. Basically each step is a different commit. So you can see the different commits down here show up. There's gonna be lots of slides with codes throughout the slide deck. All of those are links as well. So I think I've got one on the next page. No, or was it on the print? Yeah, like here. So a page like this is a link as you can see. If you click on that, it opens the exact commit where that change was done. So you can see, well, this definition was changed into this part, et cetera. So you can see exactly what went on. Those were the changes. You also see this gentleman, John Luke Picard from the enterprise come by with his famous make it show sign. You'll see that every time I've basically gone through some explanation and it's your turn to do it. I'll open up to break out rooms in Zoom, so you'll be with, well, probably three or four other people in the breakout room. I can't guarantee you were in the same breakout room every time. In principle, I'm going to leave everyone in the same breakout room, but with Zoom, if your connection drops for a bit, Zoom actually checks you out of the existing breakout room. And as I don't know exactly who's in which breakout rooms are automatically assigned, you're basically going to be added to another one that could be the same. It could be a different one, not very important, but just so you know. So the first thing we need to do is actually clone the repository. So if I go back to GitHub here and go to the root, if you click on this green button, you'll see different ways of getting the codes. And if you don't have Git installed, you can actually download a zip file, but I'm just gonna copy URL. I've got the Git URL for SSH, but if you use HTTPS, that's perfectly fine. From there, I go to terminal window and do git clone and I'm pasting that URL like that. And it's gonna clone the repository and wrap everything that's there. Not a lot of stuff, so shouldn't take very long. Where are the slides there? With that done, we need to install all the dependent NPM packages. So first we're gonna do a CD into that folder, advanced React TypeScript 2022. And once in there, we'll do an NPM install. And as you can see, at least on this slide, that didn't take very long, it just took five seconds. So let's see how long that takes now. NPM install. Of course, it's going to be slightly faster for me because I've done this before and everything comes from cache or should mostly come from cache. So it took eight seconds. It's probably gonna take a bit longer on your machine, but not a lot longer. Once that's done, basically we've got the application up and running. Now you'll be on the main page, Now you'll be on the main branch and the main branch is basically the branch which is all the completed code. So everything should work perfectly fine there. But when we actually want to get started, we want to be in a slightly different branch, which is the 00-start branch. So you can either do it with this command or what I typically do is I just start Visual Studio code, which is my preferred editor. And then down here on the left bottom, there is the selection for branches and I'll go to origins.00-start and that will switch to that branch for me locally. Then we want to start the application running.

4. TypeScript Compilation and Type Checking

Short description:

In this part, we explore the NPM scripts and run the Dev script to open the application in the browser. We identify and fix errors in the code using TypeScript's type checking capabilities. We discuss how Next.js and Create React app handle TypeScript compilation and type checking. We also examine the limitations of type checking in different environments and the importance of properly type checking all code. Finally, we demonstrate how Visual Studio code helps identify TypeScript errors.

And in here, you can see the NPM scripts. There is a Dev script there. So that's the one you want to run, either from here or from a console window. That's the default default. So either from here or from a console window. Doesn't really matter. So that's running. And now that should open up in the browser there. And you should see this list of tasks. So basically a little letter and then different tasks for go to. And you can click on the header to get back to the route.

In the start branch, there will be some errors here. Actually, there are quite a few errors, but some are pretty subtle. You won't see, but there are some others. Like if I go to inferring TypeScript, then you see an immediate error if you're on this branch. We're going to fix all of those. Some of them are more subtle. Let's show you one. Let's see. Like, here, for instance, if I order pizza with mushrooms, then we also get an error, but I have to select exactly the pizza which has mushrooms. If I select anything else, like I want this pizza with some olives, then everything works fine. So, there is an error there, but it's a little harder to find. There are a whole bunch like that, and we're gonna let TypeScript help us find those errors and fix them, because TypeScript can do a pretty amazing job if we help it a bit.

So, here's the start command if you use the command line, npm run dev, or if you want to use yarn, you can do yarn dev. The resulting application, which brings us to Jean-Luc Picard's The Make It So. The first thing I want to look at is how we can compile, or more accurately, type check the code, because we're actually compiling TypeScript to JavaScript already when we run it and then things show up on the browser, because the browser doesn't understand TypeScript itself, the additional type, annotations, et cetera. So in that respect, we're already compiling it, but we're not really properly type checking it. And you want to do that because it turns out there is already a compile error in the code right now and even though we're running it, we're not seeing that compile error. In this case, it's actually relatively harmless, but it could be something much more serious and we can't really tell, nothing to show us that there are things wrong.

Now, why is that the case? In this case we're using Next.js. The same could happen with Create React app or feeds or something else. Typically, those environments don't use the TypeScript compiler, the standard TypeScript compiler to compile the code all the time because it is relatively slow. TypeScript itself is written in TypeScript which means it compiles down to JavaScript which means that when you're running the TypeScript compiler you're basically running JavaScript. And while JavaScript in Node.js isn't exactly slow, it's not the fastest either. If you go to a lower level machine language which is truly compiled, then you can get much faster performance. Now, traditionally that would be languages like C, C++, et cetera. But nowadays there's some popular languages like Go and specifically Rust which is very popular in doing these kinds of things. And it turns out that Next.js uses a compiler called SWC which takes our TypeScripts and compiles it into JavaScripts. And I believe SWC is written in Rust. Maybe it's Go, but I believe it's Rust. But, which of the two isn't actually that important? The important thing is that it gains part of its speed by skipping some steps which it doesn't need to do. And this part which is skipped is actually checking whether the type to code is correct according to all the TypeScript annotations. Now, the TypeScript compiler can do that but, SWC doesn't do that. Create React app, which we're not using in this case but that's uses Babel. And by default Babel does something very similar. It strips all the TypeScript annotations, treats the resulting TypeScript code as modern JavaScript which it really is. And then it just transpiles that modern JavaScript to whatever JavaScript you want. So it also doesn't actually type check the code during that phase. Now, Create React app does in parallel does type checking phase on your code. But even there, that's hard to be perfect because it only checks code which you ship as part of your bundle. If you've got unit tests those will not be type checked. Next.js will type check your code when you do a build which is kind of late because you're creating a release build but there, the same is true. It will compile the code you ship as part of your bundle but not the code which is actually part of unit tests or other auxiliary code which you don't ship. So not all the code is tested. And you really want to type check that code. Now, let's see what's actually wrong. Let's actually first go to a browser. On this page there is compiled error. Yet, if I refresh this, there is nothing untoward to see. If I open up to console window, oh, it actually shows something about an uncalled error in a promise but that's actually unrelated to that error. It prints out a number one here which is interesting but also doesn't indicate any error, et cetera. So how can we detect what the error is? If I open up that index page, right here. And after a brief moment, I see a red line appear here. So I'm not sure how visible that is but down here, you can see the red line and down here on scroll bar, you can see a little red block and that's indicating a TypeScript error but that's just Visual Studio code showing me that there is an error, do the same it might not, I could use any editor I want, it wouldn't show. And if I zoom down, I can actually see here that I've got a variable called not a string, I declared as type string but then I assigned the number one to it. And if I hover over this red squiggly and it's actually shows up, it actually says here, there is an error type number from the number one is not assignable to type string from the declaration of the variable, not a string. So TypeScript infers you, well, this is a string obviously. This is declared as a, sorry, this is a number obviously. This is declared as a string and the two don't match. But other than opening this in Visual Studio code I'm not seeing anything here.

5. Compiling and Type Checking with TypeScript

Short description:

To fix the issue, we can add a 'Compile' command to the Package.json file and use the TypeScript Compiler (TSC) instead of 'next build'. We can also add a '--noEmit' flag to the TSC command to only perform type checking. Another option is to modify the code by turning the value into a string or removing the annotation. Additionally, we can add a 'compile:watch' command to keep the compiler active and automatically rerun when changes are detected. This is useful for smaller projects. In the next step, we'll explore converting JavaScript to TypeScript components. We'll see that while the rest of the application is in TypeScript, using JavaScript components is not a problem. However, to fully benefit from type safety, we'll need to rename the JavaScript file to '.tsx' and add type annotations to the props.

Well, a couple of ways to fix this the easiest is to go to the Package Json and add another command in there. So by default, we've got some scripts in here which we can run. And what I typically do is I add another one and I'll call it Compile. And by default, it comes with the suggestion to do a next build, which makes sense because we're in an XJS application. But we don't wanna do a next build because as I said that would not actually check all our code just the code that we ship.

So instead, we wanna call TSC, the TypeScript Compiler. So when TypeScript is installed we've got local command called TSC and not strictly necessary, but I wanna add not quote too much and I do want to space there. I wanna add dash dash, no emit. Strictly speaking, not necessary because there is a TSConfig file here and that already contains that, where is it, no omit right here. So that's actually in place by default but I like to add it here. So if someone looks at the script, it's clear this compiles but doesn't emit any JavaScript. With that in place, I can actually run it either through the command line or by clicking on the run command here. It runs that script and that will type check my code and report any errors. And indeed here, it comes up with exactly the same error we saw in the editor from number is not assignable to the straight, click on, I should be able to click on it and go to the offending line.

So different ways to fix it. I could turn this into a string, for instance. So now I'm assigning the string one to another string which is of type string, which is probably a bit weird. I could remove the annotation, let TypeScript do its work. So now it says not a string is actually a constant of one. Or I could say, this is some number. All different ways of fixing it. Basically that will fix it, but down here I'm still seeing that same error. So let me actually undo my fix for a moment. And let me add another command because I typically use two different commands for this. Beside the normal compile command, what I typically do is I'll also add a compile colon watch command. And that takes an additional option watch. And when I run this one, it will start compiling but the watch option will keep the compiler active and it will start watching the file system for changes. And anytime it detects a change, it will rerun. I typically use this with project, the only caveat here is with larger project or compile watch is going to take quite a bit of time. That's the reason why a lot of modern TypeScript compilers don't actually type check because of the time. So in that case, I will do the compile as a pre-commit or a prepush hook of Git, or just do it manually and do it in the CI environment. But for smaller projects like this, I'll typically have a compile watch command like this and I'll just keep it active during development. So back to the slides. Here are the two commands I added, the compile and the compile watch. The compile for, well, doing a one-off compile using it on a continuous integration server or something like that, and the compile watch for smaller projects when editing. The error we saw before. And, of course, which we can fix. So I'm going to open up the breakout rooms again for the same three minutes. Please add this compile and compile watch scripts or at least a compile watch because we'll keep it active for the rest of the workshop, because we're going to see a lot of compile errors show up when we make small changes to either the way TypeScript works or some of the code. And that's going to help us fix all sorts of bugs in the code. So let's continue with the next step.

So next step, we're going to do something relatively simple. We're going to take a look at JavaScript to TypeScript conversions, because right now we're actually using some JavaScript and some TypeScript components mixed together, which is kind of nice, that just works. So if you've got existing JavaScript in, you don't need to convert everything to TypeScript before you can use it, but there's certainly some benefits and there's some trade-offs there. So we'll look at some of the options.

Now, React components, you can write in different ways. You can use named functions, fedEral functions, they all have pros and cons. You can export and import them in different ways, which again have pros and cons. I have a way which works well for me. You might wanna do things slightly different, but I'm just gonna show you a couple of ways of doing it. Let's go to the browser first. Let's close the console window. We'll go to step one, React components or converting React components from JavaScript to TypeScript, and we've got little message component here which says, hello JavaScript. Well, as the name suggests, this component is actually in JavaScript while the rest of the application is in TypeScript.

Now, what we're gonna see is while the rest of the application is TypeScript, and as I mentioned, that's actually not a problem. So if we look in here, you can see here from the top, we're in a.tsx file also a.typescript file. This has some code in there. It renders an alert components. And if I go to that alert component, you can, if I zoom in there, you could see this is another.js, so a JavaScript file, plain JavaScript here, nothing TypeScript specific, here TypeScript or Type Annotations like this is a next page things like that, but it kind of works. TypeScript will already start validating something like let's remove that message ID because that's a required from. And as soon as I remove it, I say, we could see a compile error pop-up and it actually knows about the message ID being missing. It doesn't exactly know what it should be, down here you could see that the message ID is of type any in the variant of type any, there is no type information there at the moment. Even with JavaScript you can add type information, there is nothing here, but using js.commons, you could actually add type information about these props and TypeScript would pick those up, so that is an option. But for now, I'm assuming we want to convert all our code to TypeScript and get the full benefit of type safety. So what you'd wanna do is you'd wanna rename this file. Now with JavaScript, you can name files.js or jsx and originally the convention for React was to use the.jsx extension, but later that x was kind of dropped and everyone is just using js nowadays at least that I'm aware, very few people still use jsx. If you want to, you can, but there is really no benefits over adding or removing that x. So if I change this to.ts it might sound reasonable to do, but it's actually wrong. If I do this, my component is complied and I'll get all sorts of errors like can't find name, diff, et cetera, where with JavaScript, the extension js or jsx doesn't matter with TypeScript, it does. So I really wanted to name this file.tsx and only because of the file name tsx, with the x, does the TypeScript compiler know that this is a react components.

6. TypeScript Compilation and Prop Definitions

Short description:

I still have compile errors, but at least not as many. Let's fix these compile errors by defining the prop definitions using interfaces or type aliases. There are few differences between interfaces and type aliases, and in most cases, it doesn't matter which one you use. If a component doesn't return a React element, it will cause a compile error. By explicitly stating that the component should return a React element, we can catch these errors. I prefer using named exports and simple names for prop definitions. I also use fat arrow functions for functional components, which behave the same as named functions. By declaring the variable as an fc with a generic type of prop, we can access the component's props definition.

I still have compile errors, but at least not as many. If I do this, I also want to stop this dev task because it's still looking for that alert.js. So I want to stop this and restart this. So my Dev server's running again, hosting everything on port 3000. And it's now looking for this tsx file. So let's fix these compile errors.

Basically it says here, I don't know about message ID and I don't know about variants. It's these two props. So we need somehow to tell TypeScript what these are like. There are a couple of ways you can do it. You can define an interface and you can name it whatever you want. I typically name props and we'll add the message ID here, say it's a string and we'll add a variant here saying it's of type of string. And then we can declare debts. Parameter object is of type props. And now my compile errors go away and my code is perfectly happy. And if I go back to the browser, where was the browser window here? If I refresh it, then everything is fine. It still renders accept it isn't JavaScript anymore. So I guess we should change this message or was it to hello TSX? And that should actually change the message to hello TypeScript, this works.

Now you can define the prop definitions slightly different. You can use interface like this or you can use a type alias like this. And that's almost correct. Then it's an assignment like that. Whether you use type or interface is really a matter of preference. There's technically very few differences between the two. Interface used to be faster than type alias like this but that's also, well, even faster was relatively speaking. It wasn't exactly a huge slowdown but even that is pretty much solved. So in almost every case, whether you use a type alias like this or an interface doesn't really matter. If you're into, Oh, like you want to create a class that implements an interface or it can implement a type like this just as well or extend from one interface, extend from another interface or extend from another type, that kind of difference. One of the few I know off the top of my head if I have multiple interfaces with the same name the declarations will be merged and with type aliases like this, it's all about an assignment, they will not be merged. If I define another type here, PROP, it will be considered an error because I've got two different definitions. But it's quite rare that you actually need to do that.

Now there are still a bit of a problem, like for instance, if I removed the return statement, my component apparently is completely valid. I'm not seeing any compile errors here, is a compile error showing up, but that's not in here, that's actually where I'm using it. Over here it's saying well, alerts is not a valid JSX components, it returns void and that's doesn't really work. I guess, technically speaking, we get the compile error we're looking for, but I don't really like it. Because suppose I'm not actually using Alert by commenting out like this. I've got a error in my code, but it doesn't show up because it's only where it's being used that it shows up. So what I do is make this a bit more explicit and say, well, this is a component, so it should actually return a React element. Now, I get a compile error here. By the way, maybe you didn't notice, but it was automatically imported from React. But I get a compile error here saying, well, the function actually returns void and not a React element because of that missing return statement. So add this back in and now it's fine. But now, it's the component that in error actually causes the compile error, not if it's being used in the places where it's been used. Because if I remove this, I get the compile error here, not here where it's being used. Even if I comment this out, I still get the same compile error. Let's fix that again. You might also have noticed I'm using a named export here, not export defaults. That's just my personal preference. I prefer using named exports. Whether you use default export names, export is really up to you, there is no big benefit. You might also note that I'm using a pretty simple name for my prop definition, prop, not something which is quite common like calling it based on the components. Something like type alert prop. Then exporting that as well. The reason is if I need to get a reference to this prop definition, React actually and TypeScript gives me a much easier way to get it. If it can get to the component, I can get to the component props definition. I never export these. Although if you want to, fine, you just don't need to. But that means I can just use a simple name as prop because it's just local to this module. Typically, I don't use named functions like this very often. What I typically do is create Fat arrow functions. Const alert is react element and the fat function, which works out to exactly the same behavior. No difference, except it lets me do things slightly different. I can remove this and this and declare the property alert or variable alert, I should say, as an fc with a generic type of prop. Not like this. That should be fc, like this. And I need to resolve that. That got mixed up a bit. Like this. So fc stands for functional components. In fact, if I go to the definition, it's just an alias for functional component.

7. Defining Props and Result Type

Short description:

You specify the type of props and it will define the parameters of type prop. And it will also say, well, the result is regex element or null, the allowed values.

You specify the type of props and it will define the parameters of type prop. And it will also say, well, the result is regex element or null, the allowed values. So now, if I remove the return, again, I get a compile error saying, well, I'm assigning a function which does not match that fc definition. So a slightly easier way to do it, in my opinion. You might have heard of fc getting a bad reputation because it's not very flexible. That's true, there are some downsides to doing it. One I'll show you later in another example where we're gonna use generic components, which you can't do with react.fc.

8. Changes in react.fc and Converting Components

Short description:

The definition of react.fc has changed over time, causing breaking changes. Initially, fc would always define children as part of the props, but that has been removed. While this change makes sense for components that don't take children, it has caused some breaking changes. As long as you define the component as a React element, it doesn't matter which approach you choose. Converting a component involves following these guidelines.

Another is that the definition of react.fc has changed over the time. Unfortunately, the type information for React is not done by the React team itself, but separately on definitely typed. And because they've changed the definition of fc, all of a sudden, you would get an update and then your code would no longer compile. And one big one they recently did initially fc would always define children as part of the props and they remove that saying, well if you want children then you define props with children explicitly. Which actually makes a lot of sense technically because a lot of components don't take children and shouldn't take children, like this component for instance. But because quite a few do, it actually meant that there were quite a few breaking changes and I for one had to change a bunch of components, a bunch of prop definitions and explicitly add children. So it does have a bit of a bad reputation, still I prefer to do it this way because it is kind of clear. Use whatever way you prefer because technically it doesn't matter. As long as you define this as React element or no, actually. And technically there's actually more things you've written but that's a typical thing you should have as the result of a React component function. So that's kind of converting a component.

9. Setting Up Variant and Defining Alert Component

Short description:

Here, I've set up the variant in a slightly different way, allowing specific values to be valid. The variant is dependent on a bootstrap style, so not any string would work. Convert the alert.js file to a TSX component and explore different ways of defining it. Check the component at runtime to see the results.

Here, I've actually set up the variant in a slightly different way instead of just a string, a bunch of specific strings. That's something that I'll come back to in another model. But just in case you haven't seen this this basically means that variant can be any of these values. In this case, there are four strings here but there could be a number or so in there as well. And it's only those specific values listed are valid which is pretty neat. Especially in this case because in this case the variants is actually dependent on a bootstrap style, bootstrap class. So not any string would work there. So please make it so. I'm gonna open up the breakout rooms for one more minute. So four minutes total. Converts that alert.js to a TSX component. Play around with the different ways of defining it, you have a named function there or using, and FET arrow function like this and FC for functional component to define it and see which of those you prefer. I could go into the component and see, I could check at runtime, see what happens. Let's actually do that.

10. Mutually Exclusive Props and Message Overriding

Short description:

We're on mutually exclusive props. The message overrules the message ID, but if I specify an empty message, it's still overridden. Let's take a look at the implementation.

So we're on mutually exclusive props. And then if I open that, we can see it actually renders. Can we do mutually exclusive props, question mark. So apparently the message overrules the message ID, but what I'm using this like this, I really can tell I have to go and either check the implementation or render the component and see what actually happens. Don't override it, well, if I specify an empty message is it still gonna be overridden, or am I gonna see the hello TypeScript message now? Well, actually it doesn't, I'm getting an empty message. Let's put this back in and take a look at the implementation why that's the case.

11. Dual Alert Prop Definition and Compile-Time Safety

Short description:

I've defined dual alert, text message, and a message ID as optional strings. The actual message to display is determined by the message, with the null coalescence operator formatting the message with the message ID. If a message is specified and not null or undefined, it will be used. The use cases for passing in a message, a message ID, or both are discussed, with examples of valid and invalid cases. The addition of a variant property is also explained, with a focus on ensuring compile-time safety by restricting the combinations of message, message ID, and variant. The process of achieving compile-time safety is outlined, including the use of the never type and optional parameters. The solution provides compile-time safety and eliminates runtime errors. The limitations of restricting the message ID to a specific set of values are also acknowledged, as in real-world applications, the messages may be dynamically loaded and translated. The duplication of the variant property in the prop definition is addressed, with a suggestion to separate the properties that remain constant from those that change between use cases.

So I've got dual alert, text message and a message ID. Both are defined as optional strings. So I don't have to specify both of them, I can leave them out. And here we can see the actual message to display is the message, and then the null coalescence operator format message with the message ID. So if a message is specified and that's not null or undefined, that will be used. So an empty string was used, but if it's null or undefined, so not all passed in this case because null is not allowed, which means undefined, then we're going to call the format message function. But that means that this use case is actually invalid. And if I copy this a few times, I could make some invalid cases like this is invalid with both. If I don't specify either of them that's invalid. And if I just specify a message that would be valid, and if I just specify the message ID that would be valid. So these two are valid, and these are invalid. And there is actually a slightly more complex case where we can say there is also a variant being added, which can be, we'll say, danger for instance. This is another optional property of type variants, which was defined here, and variant is defined as any of these strings, which are basically the bootstrap styles, bootstrap variants known and supported. So, these three, these two should not be valid, but I don't really want that run time, I wanna have some predicting. That these two are not valid. And the fact what I can't even tell from this, but if I go back to the browser, it turns out I've got a run time error now, because in the last case here, where I'm not specifying either message or message ID, it actually fixed that and it works again, but I don't want the run time error, I wanna compile time error. So how can we achieve that goal? One thing we could do is say, well, these prop definitions should be slightly different. We should have two possibles. One which says we've got a message and the other says we've got a message ID, like this. So now I can pass in either a message and a variant or a message ID and a variant. Except here, I don't really get any compile time error. So that doesn't exactly help me, but in my components message and message ID are actually invalid because they're not necessarily there. So this doesn't quite work. The other thing is I want to make the message and the message ID required. So they're not optional in those cases. They have to be passed in. It doesn't fix my compile time errors here, but now if I go back to the use case, at least this is considered invalid right now. So I made some progress, but not a lot. So how do we fix these errors? Well, if I look at the error, it says, matches does not exist on type props. The same with message ID, does not exist on type props, but the variant, it's actually quite happy with. Why is that? Well, because variant is defined in both cases. And in order to solve that problem for message and message ID, you kind of have to put these back in on both cases. So now it's happy again. But we don't actually want the user to allow both of these. So we want to say, well, if you're passing in the message, then the message ID should not be passed in, which we can do by specifying a specific type here, which is never. And never is a bit of a strange type. It really says, well, you can't assign anything to this prop. We'll do the same the opposite way here. So now my message is going to be of type string here and the message ID is going to be of type string. But in my type says, well, you can never have message and message ID combined because you've either got this combination or this combination. Now if you go back here, all my component use cases are wrong. So not exactly helpful yet, we might need to make one slight change because we have to say, well, the message ID, which is never and the message here are actually optional so you don't have to pass them in. And now these top two, three cases are valid because they only have either a message or a message ID. And before I made this last change, I would have to pass in both message and message ID. But it's like in the first, I would have messages, a string, and then I would have to say, well, message ID is never, but nothing is never, so it doesn't really work. This works because I can't pass both in. Now, one would be assigned to never, which is not valid. And the empty jewel alert doesn't work because there is no value being provided in either message or message ID has to be a string. So if I did something like message is a string like that, it's happy, but without, it's not. And now I've got compile time safety. Let me comment these out, so the compile error should be gone and it works perfectly fine at run time. Let's see, there was one question in the comments. Message ID could not really be any string for format to work correctly. Yes, that's true. The message ID should be restricted to a valid ReactIntl message key. In this case, I could do that because they're actually loaded in type and then the key of type of message would work. But in most of the real applications, I work on those messages are actually loaded from a surface, so they can be translated on the fly and additional translations can be added. So you would not know them at compile time. So that suggestion might work or might not work depending on how you're using it. But in this simple application, they would certainly work. In fact, if I look where do these messages come from? They're defined somewhere in here. You could see I've got just these messages, so I can get the type of message and the keys of message and those would give me a Hello JS, Hello JSX or Hello TSX, I should say. But in this case, the thing was about doing that dual alerts. Now, this pop definition works fine, there's one thing I'm not quite happy with it although it's not a big deal right now but I've got duplication of this variant. So what we could do is we could say, well, I wanna just have that ones. So I say, I want this and I wanna have that variants so we can remove that. So everything which needs to be there all the time and I don't think we need that either, but sure once we put it back in, doesn't matter. So now I've just got the stuff that's always the same defined once which is only variant in this case and I've got the stuff which changes between different use cases separated out which makes it even better. So back to the slides. Here's an example of that's prop definition.

12. TypeScript Strict Mode and Index Access

Short description:

I did separating out two different combinations with message and message ID and adding the variants to that and the compile time error with the original code, and then of course go and fix the original code and check the various different options there if you want to play around with it. We're going to take a look at more strict features. TypeScript can be run in a strict mode. By default TypeScript is not, but if you use Next.js or create React app, then TypeScript will be in strict mode. There are some settings which are not covered by strict. The one I actually want to look at is this one, the no unchecked index access because it turns out that using arrays or things with index accessors which could also be objects, et cetera, records can lead to some problems. Let's just add some dummy code here. We'll create a new variable const data, and I'm gonna assert or create an array there with a couple of values. So three numbers in there. And if I look at data then Typescript tells me it's an array of numbers. So right here it says data is inferred as being an array of numbers. I could put that in explicitly, wouldn't make a difference. And then I could say something like const item one is data one. And Typescript would infer and say here const item one is a number, which is correct that's gonna be the number two, array zero based, so it's gonna be two. And that's perfectly true, that's a number. But I could also say item 12 for instance. Now, if I also Typescript what is item 12, it actually says, well, item 12 is a number. What is it? If I look at this array, there are just three items in there. So index zero, one, and two. There is no 13th item there with index 12. This is not gonna give me a runtime error, but instead item 12 is gonna be undefined, which I can double check if I do a console.log. Item one, item 12. And we go back to the browser. Where is it? And we actually have to go to the right page. And if I run this we see two undefined. So TypeScript thinks my item 12 is a number, but it actually prints out undefined. And if we look at the code, yeah, that actually makes sense TypeScript.

I did separating out two different combinations with message and message ID and adding the variants to that and the compile time error with the original code, and then of course go and fix the original code and check the various different options there if you want to play around with it.

So let's go and do the next step. We're going to take a look at more strict features. I mentioned in the beginning that TypeScript can be run in a strict mode. By default TypeScript is not, but if you use Next.js or create React app, then TypeScript will be in strict mode.

You can check in a TypeScript application, you typically have a tsconfig file. So tsconfig.json, like this. And you'll typically find a number of settings in there. The number can change, but quite often you'll find this setting here, strict colon true. This actually sets a number of settings for TypeScript to strict. I'm not sure how many, like 10 or so, which you could individually set to true. You can also set strict to true and then individually disable some of them. But it kind of leads you to think that if you set strict to true, TypeScript is in a strict mode and then you're all good to go, which is kind of true, but not completely because TypeScript is in a much stricter mode, but it's not like it will always do know everything there is and it's not like it can't be stricter.

But one thing you could do for instance, let's disable this for a moment, which by the way you can do normally in a JSON file, you can come make something a comment, but in TS config file, you can actually just comment outlines, which is convenient. And then you can see that I immediately get compile errors because we're actually depending on strict being true, which is the case with quite a few libraries these days, quite a few types of libraries and utilities depend on strict being true. In this case, as I mentioned, I'm using Zot for some validation and type inferencing and Zot requires we'll not complete strict true, but it requires at least some of the strict features to be set the true. In general, I recommend everyone to keep this true and only add more strictness to it, not remove any. I would only disable this if I'm doing some prototyping, but then I probably wouldn't use TypeScript. I'd just use plain JavaScript. And the other case where I might disable this if I'm converting an existing JavaScript code base and make it basically new JavaScript code into TypeScript. And then having strict rule will give you lots of compile errors. So start off by disabling it and then slowly enable feature by feature. But if you start with a new application in TypeScript, just set it to true if it's not automatically done and leave it there and not make it more relaxed. You should catch all the errors I've mentioned.

So there are some settings which are not covered by strict. And I've basically listed them, at least as far as I know this is all of them. Maybe they're actually more now because each version of TypeScript adds new features. So it's quite possible there is another one being added. And there are things like allow unreachable codes which is not affected by setting strict to true and you could disable this and not have unreachable codes without a compile error. And no fault-true cases in switches is another one which is actually quite useful. That's something which leads to quite a few bugs where people forget a break statement in the switch and actually one switch falls into the next and accidentally executes more codes than they want to. Well, set no fault-true cases in switches to true and Typescript will compile or give a compile error if that's the case.

The one I actually want to look at is this one, the no unchecked index access because it turns out that using arrays or things with index accessors which could also be objects, et cetera, records can lead to some problems. And let me show you one of those problems. Let's just add some dummy code here. We'll create a new variable const data, and I'm gonna assert or create an array there with a couple of values. So three numbers in there. And if I look at data then Typescript tells me it's an array of numbers. So right here it says data is inferred as being an array of numbers. I could put that in explicitly, wouldn't make a difference. And then I could say something like const item one is data one. And Typescript would infer and say here const item one is a number, which is correct that's gonna be the number two, array zero based, so it's gonna be two. And that's perfectly true, that's a number. But I could also say item 12 for instance. Now, if I also Typescript what is item 12, it actually says, well, item 12 is a number. What is it? If I look at this array, there are just three items in there. So index zero, one, and two. There is no 13th item there with index 12. This is not gonna give me a runtime error, but instead item 12 is gonna be undefined, which I can double check if I do a console.log. Item one, item 12. And we go back to the browser. Where is it? And we actually have to go to the right page. And if I run this we see two undefined. So TypeScript thinks my item 12 is a number, but it actually prints out undefined. And if we look at the code, yeah, that actually makes sense TypeScript.

I think someone has their mic unmuted. That sounds better. So how can we get some better type checking from that? Well, that's what that no unchecked index access does. So if I go back to the tsconfig, there it is, no unchecked index access which defaults to false. And I'm gonna turn it to true. And I'm gonna save. We're gonna ignore the compile error for now, I'm just gonna go back here. So data is still an array of numbers, that hasn't changed. But if I look at item one now, its definition has changed. It's no longer just a number, but it's number or undefined. And the same with item 12, number or undefined. Now I guess TypeScript could have done a better job in this case, because the array is declared up here on the next line, it's never gonna have changed. There's no way that could have happened. So I guess in this specific case, we could say that item one is a number and item 12 is undefined. But in almost every case, there's gonna be more going on and it wouldn't be quite that simple.

13. Validating Data and Handling Undefined Values

Short description:

TypeScript allows us to catch potential runtime errors at compile time. We can use the null coalescence operator to handle undefined values and make appropriate business decisions. By throwing explicit exceptions, we can track and fix issues using error logging systems. Dealing with undefined values depends on the specific application and the importance of data accuracy.

So TypeScript basically says, well, because you didn't check whether something you'd referenced from an array is actually a number, it's still within bounds of that array. It could potentially be undefined as it turned out item 12 really was. And it will treat it as such with the reason or with the result of possible compile errors like we see right here. And if I go to that code, we can see there is this function, getExtraIngredients. It takes a name and it returns an extra ingredient object. And let me go back to the tsconfig for a moment and disable, no unchecked index actions again. So now everything should be fine. There it is. No more compile errors. If I look at extra ingredients, it's of type extra ingredients, which is defined up here. So you can see there's a whole bunch of objects there assigned to keys. And if we dereference something, we get something of type extra ingredient and we return that. Now does it actually work at runtime? Let's see. If I order a pizza margarita with extra olives, that's fine. But if I scroll down a bit and I take this pizza al funghi and I order it, that's fine. But if I add extra mushrooms, now we actually get a runtime error. Well, that's the kind of error I want to catch at compile time that this could happen. So I can actually guard against it and take whatever is appropriate, whatever action. And that's what we'll be able to do with this. So now the extra ingredient returns a compile error. And it just takes Visual Studio Code moments to show up but now the error is here. So now we could say, well, we need to deal with this somehow. So we could, for instance, use the null coalescence operator. Let's say we've got a name and we want to add some price to it. So now if this actually returns undefined, we're going to default to a new extra ingredients object with the same name in there and an empty price. So it actually has to shape, which is defined up here, no more compile error, that's fine. If I save, my compile error down here is gone. And if I go back to my pizza application, I add some more mushrooms. Now no error, they're added, but they're free. Keep in mind what you're doing here is you're making a business decision. This is a technical solution for something which really is a business solution. Is this always appropriate? No, in this case, it's probably fine. Do I want to stop selling pizzas just because there is something wrong in my data and I can't add an extra ingredient to a pizza? Well, we're probably better off selling the pizza with a free extra ingredient. But suppose you're dealing with really expensive items and you've got some additional item which might cost you thousands and thousands of euros. You will really want to just say, well, okay, we don't know about it. I'm going to give it to you for free. Probably not. So you might actually want to do something completely different. You might say, well, in that case, I would want to put a statement in there. Say, if we don't have an extra ingredients like this, throw an exception. I was wondering why the error didn't go away, but like this. So now I'm very explicitly throwing exception which means that if I place this order, again, I'll get this exception. And presumably I'd have some kind of error logging system. This error would be tracked and locked to something like Sentry, some error collection service like that. And I could go in and fix my issue. So how you deal with this really depends on the application. But at least now we're explicitly dealing with it instead of having it's internally throw some error where you would be referencing a price from something which is undefined, which happens in a completely different place than where the error actually was.

14. Unchecked Index Access Setting

Short description:

The 'no unchecked index access' setting is highly recommended and should be added to the TS config file. It is the most important setting and helps catch potential errors. Other settings like 'no full true' with switch statements, 'no unreachable codes', and 'no unused variables in functions' are also useful but less critical. The 'no unchecked index access' setting can prevent errors caused by unchecked index access and the fix involves using the Null Code to handle errors explicitly.

So let's get back to the slides. So we saw that's no unchecked index access. Really useful, I really recommend you always add that to your TS config file and start checking for that. Of all the extra settings, it's in my opinion, the most important one. And I really don't know why they didn't just add this to strict. I would've just added it to strict and having a strict which enables like 10 options and then doesn't do important ones like this is kind of funny decision. Not sure why it was done that way, but enable this one. Take a look at the other ones. I really recommend using no full true with switch statements as well. Others like no unreachable codes, things like that, no unused variables in functions. I'm a little bit more relaxed with. They're useful, they could lead you to potential errors, but these errors are typically less serious. And it's also like linting tools like ESlint typically find those as well. They're certainly not bad to enable but they're somewhat less important. So here's the setting, no unchecked index access which I added. The fix in this case with the Null Code doing explicit error there.

15. Validating Data at the Boundary of the Application

Short description:

Validating data at the boundary of the application is crucial to avoid errors. While TypeScript provides compile-time checks, it cannot catch issues with data from external sources. In this case, we encountered a problem with the prices of pizzas, where the dot was shifted, resulting in exorbitant prices. The issue was caused by a string concatenation instead of adding numbers. Even though TypeScript was used and type-checked, the data from the backend had a string instead of a number for the price. To address this, we can use a library called Zot to validate types at runtime. By creating a schema and parsing the data, we can ensure that the types align and handle any errors that may occur.

So the next thing we're gonna look at is validating data at the boundary of the application because that's also something which often leads to errors. Now, strictly speaking, this is not very React or TypeScript specific but we'll make the bridge to TypeScript in another module slightly further down the road where we're gonna build on top of this. But first, let me actually show you the problem. Let's go to another one, validating data at the boundary. Again, pizza shop, just like before, we can add items to it. I can add pizza margarita with olives and that all looks fine. And we can go back to that pizza al funghi and I can add some mushrooms to it. And all of a sudden our pizzas become really, really expensive. It's like the dot is actually shifted over. So this is 274,500 euros and 60 cents. Not sure about you, but I'm not going pays quite that much for three pizzas. And if I look at the prices here, it actually looks quite reasonable. So something goes wrong in our application, but what is kind of hard. In this case if we just add pizza funghi we can see it's 1095, that looks quite reasonable. But if we add one with mushrooms, then all of a sudden the price jumps very much. And if I just add pizza funghi with mushrooms, we already see that. And now if I look at the numbers, 1095, 1095, 0.60. Again, here 0.6, there is an additional zero here, but kind of looks like there is something going wrong there with not adding things but doing a string concatenation. And these kind of things happen even though we've got everything in Typescript and everything is type checked. I know in the code, I'm only adding numbers to numbers. When you get data from some external source, be it the end user, be it a backend system. Then you might have type saying that it's of a specific type but that might not actually be true. And in fact, if I open up the DevTools here for a moment, I'll refresh the browser and I go to the Network tab so we can see what we loaded. If I look at extra ingredients, we can see there are extra ingredients, and let me zoom in a bit. We can see cheese has a price of 50 cents, pepperoni, 75 cents. But if I scroll down a bit, we can see that the mushrooms don't have a number as a price of 0.6, so 60 cents but it's actually a string. Now the price is typed as a number but that's a compile-time check. And at runtime, it just turns out that reality doesn't really want to conform to our types. And because TypeScript is purely compile-time check, it can't check this and it doesn't help. So we need something else there. So that was more strict validating AJAX data. And here we can see there is this loader component which uses React hook, use SWR to loads the data from the backend, and here it's loading pizza.json and here it's loading the extra ingredients. And all of that's typed, there is this extra ingredient type, which is defined here in types.js, and the extra ingredient here actually says, what price is number. But as we've just seen that JSON file being loaded doesn't actually reflect this. It actually has slightly different thing. So how can we make sure that these things actually align? Well, I'm going to use another library for that. But for that, we need to create a schema.ts file, at least we need to put it somewhere, and I typically create a schema.ts because what we're gonna do is create a Zot schema to validate our types at runtime. So I'm going to import Zot from Zot, like this, and I want to define a schema which basically looks like this for the extra ingredients. So we'll create a Const, extra ingredients schema, like this. And actually, X-ray, we'll do first a X-ray ingredient for a single one. So with Zed.object, we say we want to describe an object. So this object, so we want these two in there. And let's actually get rid of this. And we need to export this, but it's not just a string, that's going to be a Zed.string. So, Zed.string type, and the same with the number, Z.number. And that's a function like this. So that's actually defines my X-ray ingredient schema. And if I hover over that, you can see that that's a Zed.object describing this. Now I can be much more explicit. I could say this has to be, is a number which has to be positive. For instance, negative numbers are not allowed. I can say the string has to be, say, maybe a regular expression, or a phone number, or an email, or things like that. This case, I'm not gonna do any of that. I'm gonna do it really simple. But Zot is really flexible in that regard. Now the thing we're loading is not a single X-ray ingredient, but we're actually loading, where's the loader here? We're loading X-ray ingredients. So that type actually looks like this. It's a record of with a string key and an X-ray ingredient as the data. So let's create a schema for that as well. Export const X-ray ingredient schema, which is a Zot.records taking an X-ray ingredient as the value. You can specify the key, but if you don't, Zot by default takes string as the key, which is exactly what we want. So with this, I can actually validate whether the data is correct, so I can go back to this loader here, say, well, once we've loaded this, I could chain on another, then call. And we've got some data there and with that, let's switch to extra ingredients schema and say, well, we wanna parse that like this to make sure that it's valid. And yeah. Closing bracket too many. So now we're loading extra ingredients, turning it into JSON objects. And once that's done, we're parsing it and only when the result is parsed correctly, are we gonna assign it to the extra ingredients and do anything with it. And now if I go back to the application, we get a nice error message here saying something went wrong. So where does this error message come from? Basically, if I don't have extra ingredients right here, I'm displaying some kind of error message saying there was an error. So display that, and in this case, that's what we see here.

16. Fixing Pizza Price Error with Zot Schema

Short description:

We encountered an error where the price of a pizza was expected to be a number but received a string. By examining the property path, we were able to locate and fix the issue. The use of a library like Zot helps bridge the gap between compile-time checking and runtime checking. While Zot and YUP provide similar validation functionality, Zot is slightly better. In a real-life application, we would use a schema to validate all data from external sources and user inputs. The parsing of the pizza and extra ingredients in this case demonstrates the same functionality in a shorter syntax.

And the message says, well, there was something wrong. I expected the number but received a string, which was that price. And how can we find that? Well, we have to look at the property mushroom and then the property price which was exactly what we saw. And then the error message again, expected number receive string, which was kind of based here. This can be much more complex deeply nested structure with the race but basically the path will point you to whatever was wrong. The error message will tell you what was wrong. So we could basically go back here, where was the file? This one. Open that, find that mushroom, removed the quote. So if this actually a number, save this. And now everything loads fine. And if I order that same pizza with mushrooms, we get a much more reasonable although not quite as nicely formatted. Typical JavaScript's floating point numbers means that we get a slight rounding error here but at least it is a proper addition. And I guess the code would be nicer if we actually formatted the amount properly. But I left that out in this case because then it would actually complain about trying to format a string as a number. So pretty simple to do with library like Zot. And it's kind of bridges the gap between compiled time checking at runtime checking. It's not perfect yet because we currently have this type definition saying an extra ingredient should look like this. And I've got an schema saying an extra ingredient should look like that and they should match up. We don't have to do it this way. I'm gonna come back to this in another exercise and we're gonna combine these two definitions into one so you don't have to duplicate it. Because right now if I would say the price is not the number, but say a big int for instance, I would also have to go and change this as a big int. And that probably would lead to other compile errors, but don't wanna synchronize those changes. So question in the chat, instead of Zot can we use YUP? Yes, YUP supports exactly this same kind of validation. And it also supports using the TypeScript types from the Zot schema, from the YUP schema. And to be honest, I used YUP quite a lot before Zot came around. I tended to use YUP for exactly this, but Zot is slightly better. So actually switched from YUP to Zot. But YUP is going to be work perfectly fine for this if you want to. So here's the schema I defined. In this case, I've also got the pizza schema and the array of pizza schemas. But in this case, because I know you, the problem was in the extra ingredients. That's the only one I did. But in a real life application, I would do this for all data from some external source. So that would include the pizza, and I would also use this for any data the user could enter. So in a pizza ordering application, I would get their address and things like that. I would use a Zot schema or a YUP schema to validate that as well. The fix, parsing this pizza and the extra ingredients in this case, just with slightly shorter syntax, but does exactly the same thing. So please make it so. You can skip the pizza definition if you want to just do the extra ingredient because that's the only one which causes an error, like I said.

17. Inferring TypeScript Types and Limiting Values

Short description:

In this exercise, we explore inferring TypeScript types and limiting types using the 'extends' keyword. We encounter a problem in the code where TypeScript fails to pick up on a compile-time error. By using generics and the 'extends' keyword, we can restrict the valid values for object keys. Additionally, we can use generics to infer the valid values for nested object keys. This approach allows us to catch errors at compile time and ensure type safety.

Okay, so the next exercise, I wanna start looking at inferring TypeScript types, and we'll actually not in this exercise, but in one of the others, cycle back to inferring to Zot Schema types, inferring the TypeScript types from the Zot Schema. But first we're gonna do some other inferring just to see the basics, because TypeScript is really powerful at inferring types. It's like when I created cons data and I assigned an array with some numbers, TypeScript inferred that's the data was a type of number array. I didn't explicitly have to tell it that. And it's pretty good at that, but we can actually use that in pretty powerful ways.

And let me actually show you an example where we currently have a problem in the code. If I go to step five, Inferring TypeScript types. You see this blows up, but we weren't having any compile time errors. So apparently the compiler isn't picking this up. But it can. So how can we do that well, we can get TypeScript to infer types and using the extends we can limit types. So normally extends kind of means I've got, say, a class that extends another class or something like that. But in a case where you start inferring types and using generics, you can use the extent to limit something. So we might say, well, we infer a specific object key, which we're going to do in a second, but that's key you could pass in must be one of known set. So we can see say, that's the value being valid must extend a set of known values. Now, that might sound pretty vague, but let me actually do it.

I've got to code for the component you just saw blow up. And the component's pretty simple. It renders some inputs, and above it's calls this function, get conflict item for a bunch of things. So I want to get the first name, last name, birth date from a user. I want to get the employer name and I want to get the street house number and the city from an address and actually upper casing that city as well. Get conflict, there's a section, and basically reads from this object. So it was a user there, there was an address there, there are properties on there, et cetera. But if I look at, well, what's first name, it's actually being resolved by TypeScript as any, it really doesn't know what this is gonna return. If I look at get conflict item, it says it takes two parameters section and item, and they're just any strings. Facts, it says here, I can ask for an employer's name, but if I look at the conflict object in here, there is no employer. There's a user, there is an address, but no employer. And in fact, this is the one which was causing the runtime error. So if I comment that out, we can see that it actually works, and we get first name, well, last name is empty. First birthday and we're showing some kind of address. But again, I don't want this runtime. I want this compile time.

Part of the problem here is that I used any. Any basically tells TypeScript, just skip checking any JavaScript object, and basically just pretend we're doing JavaScript here, not TypeScript, which means that pretty much anything goes and anything, well, could go wrong, will go wrong at runtime, but not before. But why did I add that? Not just for fun. If I remove this, config is actually derived as being the type of that object. But down here, I get a compile error saying, well, it can't figure out what config section means. And if it can't figure out what that is, it doesn't really know what item after that is valid, what it could be. And the reason is, TypeScript knows that config is an object which has a couple of properties, but the section is defined here as a string. So it's like, well, we can't just use any string on there. It has to be one of the valid things, which is user and address. So this should have been a compile error. Employer is not valid there. How can we do that? Well, the suggestion was already made previously. We can actually determine that this isn't any string, that it's a key of the type of type of config. So I'm saying I've got a variable config, that object. Take the type from that. So that gives me a type definition of the config object. And then take the key of that, which says, okay, section can only be the first level objects on there. So user or address, which shows up. And now I get a compile time error here saying, well, employer is not valid. So that won't work until I actually add an employer there and give it something like a name. And that needs a comma. And now employer is valid as well. But I still have a compile error here. So maybe you noticed it before, but initially the Red Skull Igulies went up to here saying, well, it don't know about config section, but now it's all the way, it says I don't know about config section item. So it's slightly expanded and is now complaining about the item part. Well, I could kind of try to do the same here, but I would want to put a key of what it's, well, the stuff at the second levels of first name, birthdate, name, et cetera. How can I infer those? Or how can I make this string stricter that is actually correct? And it should be correct if the first parameter is user, then first name and birthdate is valid. If the first parameter, the config part is employer, then only name is valid. Or in the case of address, street, house, number, city are valid. I can't really do that easily. I could overload this function and write all of those different options out explicitly. But that would be very tedious. And by just changing that string, I can't do that. But when I start using generics, I can. And I can start adding a generic parameter to this function and basically grab all of this and say, this should be a generic parameter. And with generics you quite often see T, which is a terrible name. But for now I'm just going to do it briefly. So I've basically said I've got a generic parameter of section which is called T and T could be anything.

18. Using Generics for Type-Safe Configurations

Short description:

In this part, we explore the use of generics in TypeScript to create fully type-safe configurations. We discuss how to define the type of the config object and the item based on the values in the object. We demonstrate how the type checking works and how it ensures that only valid values can be assigned. We also address a compile error related to assigning a value to a birthday and show how to resolve it. Additionally, we discuss the importance of using meaningful names for generic types and clarify the difference between the section and config parameters. We conclude by mentioning the use of generics in React components and how they provide even more flexibility and type inference.

But now I'm back to the compile error about section here. So what I can say here is, so what I can say here is T can't be anything, but it extends that key of config. So now section knows that it can be your employer or address, the first level keys. With that, I can actually start expanding on this. I can say, well, then I want a second parameter. But first I'm gonna change that name because T is kind of the original name used for generic types and it's a terrible name. That's like naming all your variables X, Y, and Z. It really doesn't describe anything. So it's really the type of the config. So I'm gonna keep the T for the generic argument, although arguably that doesn't make a lot of sense, but I'm gonna call it the config with a lowercase O. We'll do the same here. So it makes a bit more sense. Now we wanna do the same with the item. We want to call this the item. So we need a definition of the item as well. Well, again, I can do an extend, but extending, yeah, what? Well, it turns out in here, I can actually use this part to index into that config object. So I can take all of this, it extends that, but not the specific config itself, but the T section, sorry, not T section, T config. So now T config is user employer or address. T item actually depends on the value of T config. So now if I go in here, I can see, well, user is valid, employers' valid, address is valid, like it was before. But last name is actually invalid because that's user only has a first name birthday and not a last name. But I could add that and it will be happy. So add a last name in there, and that's perfectly happy. But I could not say, well, let's get the last name from the employer because there is no last name there. There is only a name there. So it's completely type-safe. Turn that back into user. Now it also knows about results. So the first name is a string and the birthday is actually of type date. And I think all of these are strings as well. Oh, the house number is actually a number right here. So it actually infers the type's correct. Now, interesting, this leads us to another compile error down here. So a little further down, it says, well, we're setting the value to a birthday here which is a compile error. If we look at the value that's actually defined here as the value, which we can assign to an HTML input element which is a string, a number, a string array is valid or undefined if we don't want to set it. But something else, which object isn't valid so the birthdate, being a date is valid. So now I can turn that into a string if I want to. And because it's fully type-saved, I get the complete type checking and intellisense, like, okay, let's do that into a local. And then I can correct this. And the other rule is to add this to a string. And in my case, I want to add a romantic note, so I think I can do this. And this is what you can do with an arguing block in Jamfite. You can put that in the hunting block, because it's a counting block. That's the only reason you don't have that on your personnel. And then create a default string, using generics and type inferencing like this, inferring the type of this config object, defining the items and the sections based on what's actually in here. I remove that last name again, I immediately get a compile error here, because I'm not using, or retrieving the last name, which doesn't exist. Really nice. And we'll see some more examples of this in action. So question, wouldn't the section make more sense for the type of the section arguments? Yes, that sounds very true. Didn't I call it the section? No, it's right. This pleater right. This should be the section because it's the section parameter and not the config. The t config would for instance be the type of the config object itself. So you're completely right there. Fixed. So to change I made to the xcollgetconfig item to get it fully type safe. So please go and do this. I'm going to open up the breakout rooms for minutes again. And after that we'll continue building on top of these inferring options. But we'll do that in the next exercise. Oh, and before I forgot, I see there is another. Could this also be solved using the property path type? To be honest, I don't know. I'm not really familiar with how that works. So maybe that would work, maybe it doesn't. I would need to look interesting. I'm going to use the next exercise where we can actually make the prop type for React components and the whole component itself generic. Again, just like in the previous exercise, it will infer a type as needed. But in even more flexible level in a React component. And let me first show you where that will be useful. So we'll go to generic React prop types.

19. Using Generics for Type-Safe Forms

Short description:

I've created two forms, one for the address and one for the user. These forms are flexible and can adapt to different types at compile time. However, I want to ensure that the values passed to the forms reflect the correct types. By using generics, I can tie the prop types to the initial values and the values passed on submit. This allows for better type checking and eliminates compile errors. Although there are still some compile errors related to Object.keys, we have successfully combined the initial values and the values passed on submit.

And basically I've got two forms here. One for the address, and these are basically data-driven. So I haven't coded up this complete form. I basically code it up a generic form and then passed in the user object with the first and last name. And another instance of that same component with an address with properties. And then the adapts to. And save, but it's very flexible in that regard where they, without knowing at compile time exactly what types they're going to work against. They still give you the guarantee that's the compile time types are correct, very flexible. Show you, the current code and how we can make that better. So that's the, deriving prop types, no generic prop types. We've got this example, which we just saw two forms which takes two instances of generic form one with the user, one with the address. And this one takes an initial values which has a specific shape. And then on submit, it gets the changed values. But this you can see for when I hover over it it actually just takes values of any type. And I really want this value to reflect this type. And the same here with another instance for address. So for address, initial values is any. This is any, I want this object to be the type of value. And if I look at the actual implementation of generic form we can see the prop definition. And I can see that there are two any's here. And I really want to tie these two. Well, I can do that with generics again. So we can say the prop is a generic. Except for data type of data. And the initial values instead type of data and oops, copy the bracket too much. And the values is also a type of data. Love kind of tight, those together always going to be the same. Now, this isn't quite going to work, but if this would work, let's go back to the four, would actually right here. It would infer the type being passed into initial values. Determine that the data is this shape. And then in the submit actually said, okay, well, the values is going to be exactly that shape. But right now that doesn't work yet. It's still complaints a bit. And part of the reason is right here, it needs to know a generic type. I've defined props with generic type and here I need to add it. I can add a type in here, that's no problem. Like I could say, this is some kind of type where I hard-coded to some kind of object, but that's not going to be very useful because now it's basically going to say that my values is some objects. I really want this data type to be inferred by how this component it's being used. And that's one of the things FC won't allow me to do. So I'm going to change this a bit. I'm going to turn this into a function, a name function instead of a fat arrow function. I'm going to say, this returns a React elements. And the props are of type props. I still need that generic argument. So I'm going to put in type. And I typically use the same name. But just for clarity, I'm going to give it a different name here. I'm going to call it the type of the form data. But now I can actually put that declaration there as well. So now it's inferred from the component usage, passed on to the props used in the initial values there and on submit. So now if I check initial values is that shape, the value is the same shape. And now I actually get a compile time error here saying, well, you used last name with a lowercase N. Did you actually, went away. Did you actually mean last name with a capital N? Yes, I did. Thank you very much. Fix that error. The same here, house number, should be house number with the capital N. Fix those compile errors. And now it should work. I still have some compile errors, but first let's check whether it actually works. If I had submit, I see John Doe. If I change these names a bit, Smith as a Mark Smith. Click Submit. It actually says Mark Smith up here. So all of that works correctly, but we still have some compile errors. So it's not quite happy in here. But at least we've got the part where this initial values and the values passed on submit are combined. It's just down here, it's complaining. And one of the reasons is Object.keys, where we're looping over all the keys in the values object. And just like before, we didn't put any restriction on the generic type right away, which means anything is valid.

20. Deriving Component Props and Inferring Types

Short description:

We can restrict the object being passed to Object.keys by using a record with specific key and data types. By replacing 'any' with valid types, we ensure type safety and eliminate potential issues. The arrow function syntax can be used instead of a normal function, but the FC type cannot be used. The weird syntax with a comma after the arrow function is only required in TSX files. We will defer component types from other components to ensure proper typing, especially when using external libraries. This allows us to derive the necessary types from components or other code that may not be fully exported. TypeScript provides utilities to infer function arguments, result types, and class constructor parameters. In the case of React, inferring component props is particularly useful.

But Object.keys, if I go to the definition, you can see that the object being passed in has to be of type object, not something else. So we kind of have to put in the same restriction. So I could say, where is form data? No, not this one. This one extends an object, and now the error here is gone. We still have an error here because we're indexing into that object based on the key, and it doesn't like that. So it kind of says, well, you can't do that on an object. But it actually comes up with a suggestion somewhere in here, if I can see it, that's actually it doesn't. Should be something in here about using a record, but I'm not seeing it. But the fix is actually, well, we can't just take any object here. We want a record. Which is a specific object, which takes two arguments, the type of key, so that's going to be a string, and the type of data, which I'm going to put to any for a moment. And initial bracket, save this, and my compile errors are gone. Now just like before, any tiles, TypeScripts don't do any type checking. And that leads to potential issues, because I'm really saying, well, this value could be anything. Could be anything. So what I could do, for instance, here, say, let's go to that person, let's give him a birth date. Or let's just put a new date in here, for instance. Born right now. Well, this should give us the same problem we had before. We're saying, well, we're putting a date inside of an input component, which is invalid. So we actually want to replace this any by the types which are valid from here. So string number, read only string or undefined. Put those in. And this component is still happy but that birthday, which I added. Actually, I had a typo in the name as well, but it's invalid because a new date is no longer valid. But if I turn this into a date string, for instance, now the type of birthdate is a string and it's perfectly valid. And if I go back, it actually adds that birthday automatically for me. It just reflects over the data and shows all of them, which is really nice. So there was a comment about, you don't need to reflect to the arrow function, we could write it like that. Yeah, that looks actually good. So that might actually be a reason why you don't need to go to a complete normal function, but you can still keep it an arrow function, but you still can't use the FC, the reacts FC type to specify the component. But you're right, I didn't need to go all the way and make it normal function, I could have left it a fat arrow function. And the weird syntax is only true in TSX files because, let me actually put this on screen so you can see what I selected here, the weird syntax where you have to put a comma after it is because TypeScript gets confused in the TSX file because the angle brackets it thinks its JSX and with the comma it realizes it's not valid JSX so it's gonna use it as a generic type. In the.ts file, that wouldn't actually be necessary because you can't have JSX in there. But thanks useful additions, because I actually made the change a bit more complex than necessary, this change, the function wasn't quite necessary. So please go and do this same change, and I'll open up the breakout rooms and then after that we'll actually start using that Zot schema and inferring that as well. Actually that's not the next one, there's one before that, but we'll get to that soon enough. Like I said, we're not gonna do inferring that Zot schema type quite yet. But we're first gonna defer component types, derived components, prop types to be exact from other components, which is a very useful thing. Like I said in the beginning, when I converted that JavaScript component to TypeScript, want to print proper types, because it's not needed. With my own components, I can do so if I want to, but with many cases, when you're using components or other code from the matter from external libraries, you won't always be able to import everything you need, because not everything was exported. And by deriving what you need, you can still get at the time you might want to. The example I'm doing is with component props, but there are also standard TypeScript utilities where you can infer the arguments or the result type of a function, or the constructor parameters to a class. So there are quite a few of these, but I'm going to keep it specific to React and infer the component props. Many cases that's useful. Let me show you one of those.

21. Enabling All Checkbox Properties

Short description:

To enable all properties on a checkbox component, we can use the 'type checkbox props' and 'component props type' to infer and allow all attributes. By collecting and rendering all additional props, we can make the component more flexible. However, we need to be careful with the ID attribute, as it may be overwritten by an internal ID. By explicitly specifying the ID passed in, we can ensure that the correct ID is used. The children and specific properties like checked and unchanged are already part of the type, so we don't need to special case them.

Nope. Last pass can go away. Like we've been having some problems with ordering mushrooms, so I might want to say, well, I just want to disable mushrooms. I want to make this option for mushrooms here disabled and not order them, because it only leads to issues. So I can go into the code, say, well, we've got the pizza on menu here. And let's see, here are those check boxes for those extras. So I might say, well, I want to make this disabled, and not actually with that, with extra, is a mushroom, mushrooms. But that actually leads to compile error because disabled wasn't exposed. And if I go to the label check box components, we can see it just has a few properties on here, checked children unchanged. Well, I could go in here and say, well, in that case, we also want disabled, which is an optional Boolean. And I'll can add it here. Need a comma there. And then we add it here. And that would work perfectly fine. Now to compile error is gone here. And if I go back to the running application, I see my mushrooms are disabled, want to select those anymore. But I can still select others. But that's kind of a tedious approach because next someone say, well, I want them to read only or I want to, beside the unchanged event, I want on blur events. And I wanna expose area attributes and all the others. So adding all of those one by one and adding all those types is kind of tedious. So I'm not gonna do that. I'm gonna remove this and do it in a more flexible way. Because in reality, what I'm saying is, well, I want to enable all the properties. I can set on a checkbox there, not one specific or two specific ones. But basically I want to allow everything or maybe almost everything from a checkbox. So what I could do is say, I want the type of that checkbox props. So type checkbox props. And I don't want to start defining those here. I want to infer them. And there is a component, props type. And I can specify the type of the component I want. So the type of the component instance. And this will give me a list of all the attributes or all the props it accepts. So I could basically say, well, I want to allow some specific props or all the stuff on the standard checkbox. So now right here, Disabled is allowed and I could do Read Only for certain required or all properties show up. Well, of course they're allowed there but they don't actually do anything yet. So the simple way is to say, well, let's collect all of those props being passed in, whoops, not commas, dots, and just render all the additional props here. So now anything goes and mushrooms is disabled. And for instance, cheese is enabled. But my component is actually slightly broken now. And let me show you because one of the things I can add is an ID. And if I decide here that I want to be explicit about the IDs, say, I want the ID of the extra name and I go back here, before if I clicked cheese it would actually select the item. Now we actually have to click on the little checkmark. Why is that? If I inspect, we can see where's the input here. It has an ID of cheese but the label has an HML4 attribute of colon RB colon. So where does that come from? In the labeled checkbox, we're actually using an internal ID and not the ID passed in except that's part of this prop. So this actually overwrites the internal used ID. So I want to be a little bit more explicit about the ID being passed in and use that as is. I can't do this. So if the ID passed in, then otherwise use the one from the used ID which gives us the pet ID cause that will conditionally call this and conditionally calling this is not allowed but we can do this where we're using it. So do that in there, in there And now this is fine except for some reason it's complaining here, actually that shouldn't be an or, that should be an and. Now it's happy. And now selecting something by the label should work again. And we can see in here, the ID is cheese and the HTML4 attribute is also cheese. So they're right there again. So better, everything works now. Leave it like this, if you look, well checked, it's just a standard property over here. I'm just passing that on as is unchanged the same. So do I really need to special case those? No, they're already part of this type. So I can actually get rid of the children as well. So it can get rid of those, which means I've gotten empty object. Empty definition which actually means that I don't need anything special there, I can just do this. So that shortens that. Anything special with checks or the unchanged. So I can kind of say well, we'll just collect those in all the props and pass them on. Do you think I need to space is the ID. If I overwrite that, I wanna use that. And the children because I wanna pass the children on to the label and not to the checkbox itself. And now everything still works. Different items are there.

22. Infer TypeScript Types from Zod Schemas

Short description:

Component props take any component, even functions. The parameters type helps define function types. Zod schemas can be used to infer TypeScript types. Updating the schema updates the type. TypeScript can infer types based on other things. Duplication can be reduced using type mappings in the next exercise. The difference between type and interface is minimal.

Mushrooms are still there. If I add something, it's still added. So that checking actually works. And all because of a really simple thing. Component props just take whatever component you want, whether it's something I defined in my own codebase, whether it's from some library, doesn't matter. It will just work on any component. If you've got a function, you could kind of do the same. Suppose we've got a function demo, which takes argument say, S is a string. Doesn't actually do anything, but I could do something like, what was it? Parameter types. I thought it was parameter types, but now I forget the actual name of the generic where you can type the parameters. I'll look that up in a second and I'll add that just to show you. But lots of functions like that which are really useful.

Here are the updated label check box, much more flexible. Let me quickly show you what I did wrong. Like there is a parameters Typescript type, which lets you take a type of a function and it will tell you which parameter it is. You see, I've got a function defined to stacking a string and the number and it actually returns to string. So it's inferred as returning a string and with parameters, you could see it's an array as n string number, and you can index into them, get specific ones like this or get the result from the function, which is string and then, or if I change this to return n, then I check results and that's actually number. But the thing I was doing wrong and that happened to me before, that's something to beware. If you just start typing parameter, like it doesn't show up in the intelligence list. You really have to make sure for the TypeScript realizes that you're working on a type definition. And then if you do something like that, now parameters shows up, or return type, things like that. But without the type t or type something in front of it, it doesn't show up in the intelligence list. And that was throwing me off because I was just typing parameter, et cetera.

Let's go to the next exercise, we've got like 50 minutes left, well, little less than 50 minutes for the last part. Like I said, we're gonna to everything, but we will be able to do a bit more. Remember the free coupon code you have for the online course where you can see all of this, most we won't get to. So I mentioned that having the Zod schema and the type definitions and keeping them in sync is tedious and we actually can defer quite easily from the Zod schema. And that's what we're gonna do right now and something which I do quite a lot in real applications. It's not like every type I'll create this old schema for, but every type where validation makes sense, I create this old schema for and then just infer the type. And inferring it is really simple. Let's use Z.infer so it's supposed to infer from Zod. Z.infer type of some schema definition and that will give typescript type back. So let's actually do that. Let's close these and go to the next one. Here we've got the Zod schemas, just like we saw before with extra ingredients. The extra ingredients records, the pizza schema, pizzas as an array of pizzas, all used for validating. And we've got the types, which are kind of related, well, we kind of want to define those separately. So import and then the pizza type, we don't want to get this way, we want to do that dot infer and then type of pizza schema. If I hover over pizza, you can see. Get rid of this. We do the same for extra ingredients. Ingredients, plural, schema, for the extra ingredient. And for the pizza, we want the schema because they're never imported. See those are imported. See that looks like a wrong import, so let me quickly fix that. That should be from the schemas in the current folder. So now I can see all the types with a simple definition. And now if I decide I want to make a change, say I want the price not to be a number, but to be a big int. I define it in the schema. I go back, check the price and now right here you can see the price on the pizza has become a big int. Much easier, much more convenient to do. Let's turn this back into a number because a big int as you can see from the compile errors it actually goes through some other errors. Pretty neat, pretty convenient. Again, another nice case for TypeScript can infer types based on other things. The implementation of an infer is not super simple here but still pretty powerful. Still got a bit of duplication that I don't like. We've got a pizza on order where we've got the pizza name and price which the type having to match up with pizza because if I would change the price to be big I would also have to change this one but we're actually gonna look at that in the next module where we're gonna create types based on type mappings again but in a slightly different way create one type based on the shape of another type but only take part of it. But that's for the next exercise. So let's go back to the slides and we can see the definitions of the pizza and the extra ingredients type just like we did. And there's Jean Luc Picard. So please go and make this change to those types. And that question was could you explain the general rule of typer's interface? In a way very simple and in a way quite complex. The complex thing is seeing difference between type and the interface. Because the simple part of the answer is, well, most part there are no differences you can use them next. Like for instance I've got an export type pizza order, I can just do this, remove this equal sign and now an interface instead of a type. No problem, no difference. It will work exactly the same. One thing though I can do now is I could for instance say, I wanna duplicate this. And now I've basically defined my pizza order in two separate blocks. I've got, can I see the complete result of pizza on order now somewhere? Probably.

23. Merging Interfaces vs Types

Short description:

When using interfaces with the same name, they will be merged into one, but if using types, they won't be merged. This can lead to duplicate definitions.

Let's see. Order pizza. Will it show me? No, it still only shows me the type. But the fact that there are no compile time errors kind of tells you enough, because if I would remove this and save I'll get compile errors. And if I remove one of these two I'll also get compile errors. So what happens is these two interfaces because they're named the same, they will be merged into one. If I turn this back into a type, that won't happen. So do the same there. Now TypedCrypt is basically complaining, saying well I've got a duplicate could identify our pizza on order. So these two type definitions are not merged. I really had to define it. So that's a difference. Is that important difference? Probably not.

24. Type Inference and Mapping in TypeScript

Short description:

When inferring and mapping types in TypeScript, we can use utilities like omit and pick to create new types based on existing ones. Omit allows us to exclude specific properties from a type, while pick allows us to select only certain properties. These utilities provide flexibility and help ensure type safety. TypeScript provides other mapping utilities like record, exclude, and partial, which can be useful in different scenarios. We'll explore more mappings in the next exercise. Another useful type mapping is the read-only type, which allows us to turn a mutable object into a read-only object. This can be helpful in cases where we want to prevent accidental modifications to certain types. Let's dive deeper into read-only types in the next exercise.

Another difference here, I'm inferring based on the schema type, and that will always create a type alias for me, never an interface. So I get error, compile error, saying well, I can't do that. If I define an interface, I have to start with compress. I cannot add something to that like this. What I can do is I can say it's some kind of object and then I can add this, actually it doesn't like that. I was expecting it to be valid. I guess that isn't even valid. But as soon as mapping types, inferring types like that, you always end up with the type alias. It's always type never extends, so that wouldn't have worked. Yeah let's try again. I guess not, actually this has to go after it. But it does work, this way it does work with extents. So next thing I want to do is again, create a new type, but now for the pizza which was ordered, which is this name, the price which has to map to the actual pizza type. And then add some more to it, the extra ingredients, which does actually have a different shape. And they're used by standard features like omit and pick, where you can take an existing type and say, I want parts of that as a new type. So I could say, well, pizza on order, consists of name, price, extra ingredients. I could get rid of these, well, it should be pizza and that extra ingredient, but now if I look at the type, you see, I've got name, price, which I wanted, but I've also got ingredients and extras in there, which I didn't want. So, for instance, with omit, I can say I don't want specific properties from there, so I could say omits the ingredients. Why isn't it showing up? It should be just ingredients. And now the pizza on order is actually simpler, although it's pretty hard to tell from this, because what you see is how the type is defined and not what the actual result is. This isn't going to give a compile error, but say I remove the price. It actually needed. Now you can see that we get compile errors. And I can do multiple properties if I want to do. So I could do omits price or for instance the name. Now both of those are omitted. In the end, the extra pizza on order will contain extra ingredients and extras. Because in this case, this is actually exactly the properties I want. So instead of omits, I could use the pick utility and pics as well for pizza take the properties I list after here. So take the property which is either price or name and use those. And now if I compile, everything's fine again and the pizza on order looks exactly like what it should be. So very useful. There are actually a whole bunch more. Like let me quickly go to the definitions. If I go to the definition, I press F12 on Windows. You can see the respect, there is a record to create a record type, which we'll really use. There is an exclude, there's only we use in the bit. There's things like a partial to grab a type as a, we'll take all the properties but make them optional, not required. What else, to make things not nullable. So this already the parameters, uppercase string which can be useful if you get into string type. So all sorts of interesting maps you can use. Yeah, there's another mention in the chat about an Xpand for cursive, which shows how to do things. Oh, actually I've got some examples on how to do that if we get to it. But first, let's go back to the slides and see the change I just made. So we pick from pizza, the name and the price. When I have to choose between pick and omit, I typically go with, well, do I want everything from a type except some things? And if that type is expanded, do I want to automatically also add those new properties Or is it the other way around? If I expand the type and new properties are added, do I want to ignore them unless specifically added? In this case, I'm specifically interested in only the name and the price. And if I add new properties to pizza, I don't want to add those to the pizza on order by default. So I'll use the pick. But if it's like I would want to add them by default, then I would use the omit instead. So please go and do this. I'm going to open up the breakout rooms again for three minutes. After this, we'll take a look at some more mappings to read only I just mentioned to see how that will help us find even more errors in our code base. But that's for the next exercise. So the next exercise, I want to take a look at another type mapping, which I briefly showed in the definition file just now. So read only type mapping, where you can take a shape of an object but turn it into a read only type. And the reason that's useful is by default, TypeScript is very much like JavaScript, which makes sense because it's a superset of JavaScript. And in JavaScript, everything by default is updatable. But if you start using TypeScript, you want to declare what your type should and should not do. Well, having all your types just as read, write, and updatable doesn't always make sense. Like, there are cases where that's perfectly valid. But there are also a lot of cases where that's not so valid. Let me show you one case where that's valid. I'm using it only. Step 10. So I've got another instance of the pizza shop, and I could say, well, let's order some olives. And I've got the pizza margherita, $7.95. All $0.6855. Place the order. Ah, you know what? I like them. I want another one.

25. Preventing Unintended Modifications with Read-Only

Short description:

To catch the issue of the price being assigned instead of compared, we can use a read-only mapping to wrap the type. This will result in a read-only name and price. By making the array of pizzas read-only, we can prevent new pizzas from being added. However, the elements inside the array are not read-only. To create a nested read-only structure, we can use a deep-read-only mapping. This can be useful in cases where we want to prevent unintended modifications to specific types.

All of a sudden, it's become more expensive that olives, which were $0.60 just now, are now one euro. Turns out, but the compiler could catch that, but doesn't. So let's go and help the compiler a bit to catch that. And what actually happens is we've got these extra ingredients. But the extra ingredients, the price is being updated because of a little slippery in the code. But because it's a redirect type, TypeScript thinks, well, that's perfectly fine. The runtime, of course, doesn't care about read-only at all. You could use object.frees to prevent it, but that either. But I could say this is read-only. Wrap this whole type inside read-only mapping. So the result is, as you can see here, a read-only name and a read-only price. Now, if I save this, I just hit Control S, we immediately get a compile error, we are saying that the price is being assigned to. And if we go to that code, I've got some stuff here, extra for a euro, and I do an order.flatmap, and then a.filter, and then I look all the extras that cost a euro. So based on that, I'm doing a filter. That kind of suggests, okay, I want to compare the price to one, not assign it to one. But because the price was updatable, I was actually by accident assigning it, and instead of a single equals, I wanted to use a double or, even better, a triple equals there. Make that change. Compile error is gone. Go back to the browser. That's refreshed, so we're in a clean state. Add a Pizza with Olives, 8.55. Order another one. And it's another, a bug in here actually. So, let's actually do it with this one. Cause this, the price itself is also updated, but the price of the olives stays the same. That stays 60 cents. But there is another bug here where the price of the pizza itself actually changes. But we'll do that in the next exercise because the, we only type is really nice, but it's only for a specific object. It's not recursive. And it turns out that's using. A, push itself. They also are removed. So it's not just for, it's for complex things as well. But if you make an array read-only, then the elements inside of that array are not read-only. It's one level, not recursive. Read-only is pretty useful, I mentioned, but not nested. How hard will it be to create a nested person? You can create a deep read-only. And the example was actually from this link. There is this guy called Basarat. He tweets a lot, but also makes pretty useful YouTube videos. So following him in YouTube, and on Twitter is highly recommended. And in that case, he has types recursive nested read-only. But I'm actually just gonna go to the, by hand, it turns out it is extremely simple. And cases like that are simple, but first let me show you why we would want to do so. Like I previously showed, if I add an order with pizza or burrita, and I add another, it becomes more expensive. And every time it's becoming more expensive, like 7,950 euros for pizza is kind of steep. But there is also something else going on. Let me refresh the page for a moment and go to the bottom. Let me add a pizza Hawaii. And notice I can't scroll down. Scrollbar is right at the bottom of the page, nothing loaded. I add that order, and all of a sudden I can scroll down. There is a new pizza being added. Yeah, I'm at the bottom, and another one has been added. So every time I order something, a new pizza is being added to the list. That probably shouldn't happen. So, both of these cases are things that shouldn't happen. Now, we can say, well, we got the pizzas, and we want to make those read-only. Well, first let's start with the array of pizzas. So, we've got the menu here, so I want to make sure that this is read-only. Read-only array of pizza. And as soon as I save, we get a compile error. And if I check, we see here that in this base of code, where we placed your order, we're pushing a new pizza in that array. So, that's one problem solved. Let's comment this code out, and that should take care of adding new pizzas. So, if I scroll down to the bottom, take the last one, place an order, no new pizzas appear. We still have the problem here with the pizza margarita that keeps on getting more expensive, and there no more compile errors. So, let's actually go back to the types and take a look at read-only. It's really simple. So, I'm just going to copy it into our own code, and I'm going to call this deep-read-only for a deeply nested structure.

26. Exploring Deep-Read-Only and Resolve Utility

Short description:

In this part, we explore the concept of deep-read-only in TypeScript. By applying the deep-read-only modifier, we can make nested properties read-only as well. This ensures that any changes to nested objects are prevented. We also discuss the use of the resolve utility, which allows us to see the actual resolved type of a complex structure. This utility helps us understand the resulting type after applying various type operations such as pick and read-only. The resolve utility is a powerful tool for type inference and provides insight into the final type structure. Lastly, we briefly mention the type predicates and assertions, as well as exhaustiveness checking, which are covered in more detail in the course.

Export this, and in the menu, I'm going to turn this into deep-read-only. So far, I haven't achieved anything. There are no differences because read-only is just a copy of what the original read-only was. But what I can do now is I can say, well, everything in here nested, every property also becomes read-only, which means it will loop over any object in there. So, if there are any nested objects in there, they will again become read-only, and that will go through however nested many levels you want. So, if I save this, we immediately get a couple of other errors. The second one we'll fix in a moment. But this one, where it says, well, we can't change the price and we're actually changing the price on the first beta, multiplying it by 10 every time. That's an assignment we don't want. So, let's actually go there, pizza shop, and that's the second thing. There are two more errors we have to solve. You can actually solve that relatively simple. Right here, we've got the pizza, which is a deep root only pizza and we're adding that to the pizza or menu. But if we look at the definition of that, that's just a regular pizza, which means we're taking a read only version of pizza and assigning that to a non-read only version. So, in this component, we could theoretically start changing that pizza. So, by adding the deep read only here as well, that should be fixed and safer as well. And fix my typo. So, now those errors are gone. And if I accidentally, for some reason, I wasn't doing that, but if I did something like pizza.price is one, for instance, now right here, that's a compile error saying, well, it's read only, it can't be changed. And if I undo this change for a moment, now this would be perfectly legal. You shouldn't do that. Never in React, change props being passed in, but TypeScript thinks this is legal because it isn't aware of that rule. And now it won't, it will stop us. So no more compile errors. The problem with the pizza margarita should be gone. 795, it's still 795. So by adding a bit more explicitly what we intend to do with types in TypeScript. We actually found two more books in the code, which is pretty neat. Now, in the interest of time actually gonna change this for a moment to what we had before. Because we've just got 10 minutes left so I won't be able to demo this and I think it's kind of nice. Here, I had the pick of the pizza and I want to the price and the name and pick with the K, not an L. And like what I was previously mentioning, if you look at this it's hard to see some. Well, pizza is read only so we'll make this read only if I can type read only. That's lowercase O, yeah. So this pizza only becomes read because now we can see how it's defined, it's a pick read only of properties with some picked and then some other stuff added. But what does that actually result in? Well, I can't really tell without manually or at least in my mind going through all the stuff in there, which is kind of hard. Now let me skip ahead in the slides a bit to the next part where I was gonna display the type because there's this other really neat utility, Resolve, which is from Dan van der Kam in his book, Effective Type Script. And if you scroll down a bit, there is this resolve type, which basically says, okay, resolve a type from its definition to what it's actually defined as. So I'll copy that, paste that in there. And now I'm basically gonna wrap this whole structure inside of resolve. If we look at the pizza on order now, I don't see read only or mid-pick, any of that stuff. I see kind of what it boils down to with name, price, and next ingredients. I can't see the details on the extra ingredients yet because the structure isn't recursive, just like with the deep read only, I can say well also go and resolve the nested stuff in there. And now, if I look at the pizza on order, I can see exactly, well, there was a read only name, price, there's an extra ingredients, but not read only, there is a read only name and price there. So apparently this should also be a deep read only in order to make the extra ingredients read only, or I just specified in here like that. So now I get to see exactly what the result is. Now someone pasted a type definition, which I'm not familiar with in it, but I suspect does exactly the same thing, so let's see. If I use that, yeah, it does exactly the same. So different way of achieving the same goal. I'm not sure why the one from the special cases functions, I don't think it actually needs to. I think if a change is back to resolve and actually say, well, forget about the function, we'll forget about the function parts that, well, this case, it's certainly gonna work because there are no functions in there. But I think in other cases that will work just as well. I've never really investigated that I just used this as is with the nested structure on there. Interesting, it gives you no runtime overhead because this is purely TypeScript and it's gone at compile time. It does make compilation slightly slower, but I think the fact that you can see what the result is makes it really powerful over having to infer yourself what the result of all that pick and read-only, et cetera. So, I typically use this quite often on Types to see this stuff. So, we've got five minutes left. Let's do these last two exercises in one go, adding the resolve, or this expand recursively, whatever you prefer. That's in the chat window. So the useful alternative. As far as I can tell, there was no benefit to one or the other. They do the same thing. And at the same time, add a deep read only to find the two bugs in the code, which I just fixed. And then after that, we'll wrap up the workshop. And then, I remember we skipped, so we didn't get to the last part, but you'll have coupon code for the course. And I already noticed from my alerts on my phone that quite a few people already registered for that, but that's fine. That's what it's for. So I'm gonna skip over the last bit, which is interesting, but unfortunately we didn't have time to cover everything, which I predicted upfront, but that's what the course, the online courses for you can still see those modules there. There are about the parts down here. Where's my mouse there? The type predicates and assertions, which will give you both compile and run time safety, and then exhaustiveness checking to make sure where you add something, for instance, to an enum, and you need to cover all the cases with say a switch statement, and you've expand the enum that you don't forget to expand to related switch statements.

27. Conclusion and Gratitude

Short description:

We covered cases where bugs in code were identified and resolved using additional TypeScript settings. Validating data at the boundary and resolving TypeScript types based on schemas were demonstrated. The possibilities of type mappings are infinite, allowing for programmatic access and the creation of a fully functional type or programming language. The workshop concluded with gratitude for attending and encouragement to explore TypeScript and React further.

Useful, but no time for that now. So we did cover a lot of other things. We covered a lot of cases where there were bugs in code and with some additional settings for TypeScript, either by making things explicitly read-only or setting that no unchecked index access setting, we can make TypeScript find a lot of potential bugs and point them out and make us think about better ways to solve them than just letting it happen at run time.

We saw how we could validate data, the boundary, not specific to TypeScript or React for that matter, but still very useful, something I do a lot. But we also saw how we could actually resolve TypeScript types based from those SOT schemas, which is really neat. And as I mentioned, that's not specific to Zot, you could do the same with a Yup or there are several other libraries which can do that as well. But Zot is as far as I can see, the best one out there at the moment. And give you perspective on that, I'm actually one of the maintainers of the Zot, sorry of the Yup Type libraries in Definitely Typed because originally Yup was written in JavaScript, not TypeScript. It has been rewritten in TypeScript. But even though I maintained those, I actually switched over from Yup to Zot.

So we saw a lot of map types like pick, read-only, how to create our own with deep read-only, that resolve, things like that. The possibilities are infinite. Like if you wanna play around with types, you can do whatever you want. Basically, the type mapping system allows for programmatic access. You can do conditionals there. You can infer types. You can do all sorts of things, and do very interesting things. So you can turn TypeScript type system into a fully functional type or a programming language, which is actually completely valid Turing complete language. So the end, the possibilities are, well, whatever you can imagine. Much, much more than we went into or even possibly could cover in a few hours.

So with that, I'd like to thank you for attending this workshop. I really enjoyed preparing it and looking up all the capabilities and sorting it out to present stuff. I hope that you picked up some interesting tips on how you can use TypeScripts with React or for that matter, how you can use TypeScript without React, because very few of these were React specific. It's much more generically applicable. Of course, things like component types is React specific inferring component types, but almost everything we covered will work outside of a React code base, which is really nice. Thank you very much for attending. Enjoy TypeScript, enjoy React and happy coding. See you all some other time.

Watch more workshops on topic

React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Featured WorkshopFree
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Featured Workshop
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.
You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.

React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.
The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.
React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.

React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Featured Workshop
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents
- The different kinds of React application tests, and where component tests fit in
- A mental model for thinking about the inputs and outputs of the components you test
- Options for selecting DOM elements to verify and interact with them
- The value of mocks and why they shouldn’t be avoided
- The challenges with asynchrony in RTL tests and how to handle them
- Familiarity with building applications with React
- Basic experience writing automated tests with Jest or another unit testing framework
- You do not need any experience with React Testing Library
- Machine setup: Node LTS, Yarn
React Advanced Conference 2022React Advanced Conference 2022
148 min
Best Practices and Advanced TypeScript Tips for React Developers
Featured Workshop
Are you a React developer trying to get the most benefits from TypeScript? Then this is the workshop for you.
In this interactive workshop, we will start at the basics and examine the pros and cons of different ways you can declare React components using TypeScript. After that we will move to more advanced concepts where we will go beyond the strict setting of TypeScript. You will learn when to use types like any, unknown and never. We will explore the use of type predicates, guards and exhaustive checking. You will learn about the built-in mapped types as well as how to create your own new type map utilities. And we will start programming in the TypeScript type system using conditional types and type inferring.
React Day Berlin 2022React Day Berlin 2022
53 min
Next.js 13: Data Fetching Strategies
- Introduction
- Prerequisites for the workshop
- Fetching strategies: fundamentals
- Fetching strategies – hands-on: fetch API, cache (static VS dynamic), revalidate, suspense (parallel data fetching)
- Test your build and serve it on Vercel
- Future: Server components VS Client components
- Workshop easter egg (unrelated to the topic, calling out accessibility)
- Wrapping up

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2021React Advanced Conference 2021
39 min
Don't Solve Problems, Eliminate Them
Humans are natural problem solvers and we're good enough at it that we've survived over the centuries and become the dominant species of the planet. Because we're so good at it, we sometimes become problem seekers too–looking for problems we can solve. Those who most successfully accomplish their goals are the problem eliminators. Let's talk about the distinction between solving and eliminating problems with examples from inside and outside the coding world.

React Advanced Conference 2022React Advanced Conference 2022
30 min
Using useEffect Effectively
Can useEffect affect your codebase negatively? From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. In this talk, we'll demystify the useEffect hook and get a better understanding of when (and when not) to use it, as well as discover how declarative effects can make effect management more maintainable in even the most complex React apps.
React Advanced Conference 2021React Advanced Conference 2021
47 min
Design Systems: Walking the Line Between Flexibility and Consistency
Design systems aim to bring consistency to a brand's design and make the UI development productive. Component libraries with well-thought API can make this a breeze. But, sometimes an API choice can accidentally overstep and slow the team down! There's a balance there... somewhere. Let's explore some of the problems and possible creative solutions.

React Summit 2023React Summit 2023
23 min
React Concurrency, Explained
React 18! Concurrent features! You might’ve already tried the new APIs like useTransition, or you might’ve just heard of them. But do you know how React 18 achieves the performance wins it brings with itself? In this talk, let’s peek under the hood of React 18’s performance features: - How React 18 lowers the time your page stays frozen (aka TBT) - What exactly happens in the main thread when you run useTransition() - What’s the catch with the improvements (there’s no free cake!), and why Vue.js and Preact straight refused to ship anything similar
React Summit 2023React Summit 2023
24 min
Debugging JS
As developers, we spend much of our time debugging apps - often code we didn't even write. Sadly, few developers have ever been taught how to approach debugging - it's something most of us learn through painful experience.  The good news is you _can_ learn how to debug effectively, and there's several key techniques and tools you can use for debugging JS and React apps.