Power Up React With TypeScript
with Ben Ilegbodu
Want to add autocomplete, better linting, and more to your React apps? In this episode, Ben Ilgebodu teaches us how Typescript powers up our React apps.
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON LENGSTORF: Hello, everyone. And welcome to another episode of Learn With Jason. We have Ben Ilgebodu. Ben, thank you so much for joining us.
BEN ILGEBODU: Of course! Thank you for having me. I'm excited.
JASON LENGSTORF: I really appreciate we were supposed to do this a couple weeks back and it was all smoky on the West Coast.
So, Ben, for those of who are not familiar with your work, can you give us a little bit of a background?
BEN ILGEBODU: Sure. So, like you said, I'm Ben Ilgebodu. I work at Stitch Fix, I'm a principal frontend engineer there. I am on our I guess you would call it our Platform team. I don't work on direct user features. I work on the stuff that enables my teammates to build features for our users, so that's our design system I've been working on for about a year. That's in React. It's also in TypeScript. Kind of the motivation for us hanging out today. (Laughter). The other side of it is what I call DivOps, not DevOps.
JASON LENGSTORF: So, like Chris put out this whole post about, you know, the evolution of frontend development and how it's gotten so much bigger, right? So what you just said touches on I think one of the most surprising parts of frontend development is there's now, like, a backend development for frontend development. Is that what you're talking about with DivOps.
BEN ILGEBODU: Basically. It's your webpack configurations. Setting up ESLint rules. So, we're trying to consolidate how all of that works. Quite frankly, not everyone wants to know how that stuff works.
JASON LENGSTORF: It can be a lot.
BEN ILGEBODU: It is key for your app to be performant. It's a core competency and I'm seeing some companies even, like, having roles for just that sort of thing. I'm working on this, like, backend and I'm working with our designers, writing components for our design library component library. It's this whole breadth of stuff, not to mention the actual building of UIs. It's getting bigger and bigger.
JASON LENGSTORF: Especially as we're moving into this world of you can build entire things on the frontend. It's no longer something that you would take to, like, a Java architect, right? If you're looking at big, oldschool enterprise companies who have a lot of software architect, using hardcore backend languages, it doesn't make sense having the architect designing the frontend apps.
BEN ILGEBODU: We have those architects at Stitch Fix and they help with setting up our APIs because our APIs are inhouse so we still have to make sure those are correct and how all of the systems are working together is important.
But, like, to your point, not those people, yet, haven't understood what's going on in the frontend. A lot of it is communication about how it works so they can lend their expertise.
JASON LENGSTORF: And a lot of what you're talking about here, I think, is really interesting. You said "communicate how the stuff works." Maybe your experience is going to mirror mine, here, but what I found is a lot of the foundational stuff we do, the DivOps work, it's trying to set up guardrails and guide people down the right path so they don't get themselves into trouble.
How actually, that kind of ties into what we're going to talk about today. What kind of tools are you using and what approaches do you take to make sure you're setting people up for success on your team?
BEN ILGEBODU: I have this mentality, I'm planning to blog about it. I like tooling over documentation. So, docs are great, but the docs are like, "here are our best practices on how we do X or you should never do Y," if I can create tooling to enforce that, that's so much better than trying to have documentation that goes outofdate in three months, six months or whatever. ESLint is a perfect example of that. Some of it is errors, some of it is styling. Some of them are you might shoot yourself in the foot if you're doing this so we're going to have an ESLint. TypeScript is another perfect example. Using "double equals." TypeScript is going to enforce a lot of these Type things we try to push in Lint rules or communication, that I think is really helpful, so, less things more things that automation can do and GitHub checks can do the better.
JASON LENGSTORF: Absolutely. And that makes sense, right? In my job, I get handed a million things that I'm supposed to know and pay attention to and read and comprehend and there's just no way I can do it all. If we, as engineers, can kind of smooth the path and take away some of that thinking so that the software kind of writes itself because I can't push it otherwise, that's a great thing for me.
So, how does TypeScript tie into that? Like, what are we able to do with TypeScript that makes it worth the effort of switching?
BEN ILGEBODU: First, I want to preface it that there is effort. I don't want to gloss over that or anything like that. It's definitely effort. It's worthwhile in my opinion. It helps prevent those times where we shoot ourselves in the foot because we're being too clever or we forget about this certain aspect. I'm pretty sure this thing's never going to be undefined so I'm not going to check it. Things like that. (Laughter). Even in React, this prop was never declared in the prop types but it's used in the code. It's not marked as "required," but it's definitely used as if it's required. That's just a recipe for disaster. If TypeScript can enforce that when I call this component, I have to pass in this value.
There are new things, like interfaces that exist, but mostly it's all around being able to declare types.
JASON LENGSTORF: Awesome. Okay. So, chat, as always, thanks for hanging out with us. I want to take a quick minute to shoutout our sponsors. So, let me switch over into this view. First of all, everybody go follow Ben. And, remember, the captions are available at lwj.dev/live. What's going on here? Why don't you think we're live? Oh, that's no good. Um
BEN ILGEBODU: We definitely are live. (Laughter).
JASON LENGSTORF: Twitch, are you bugging out on me? Oh, that's a bummer. So, I'm going to have to hey, White Coat, can you send me the link to the iframe that I usually embed here? That is made let's see, I'm just going to type this up. It is StreamText.net. It is event: LearnWithJason. If you want to watch the live captioning, it's going to be right there. You can follow along in a browser of your choosing. I will figure out why Twitch has betrayed me today.
The live captioning is made possible by the generous sponsorship of Netlify, Fauna, Sanity and Auth0, who have all kicked into make this show more accessible to more people and that is providing by White Coat Captioning.
With that being said, why don't we jump right into this. So, if I'm ready to start, like, I want to write a TypeScript project, but I haven't done it before
BEN ILGEBODU: Yep.
JASON LENGSTORF: How should I get started? What's the first thing I should do?
Then, typechecking still happens with the TypeScript Compiler. You can stay in your Babel universe. It's pretty sweet. But to start with, don't worry about all those things. Those are DivOps land again. We can use Create React App to create it. We'll find the template, here on the docs, as we go.
JASON LENGSTORF: All right. So, there's a whole bunch of stuff here. Maybe I want to look at
BEN ILGEBODU: They have the search at the top. Maybe type "TypeScript" at the type there.
JASON LENGSTORF: Using TypeScript with Create React App. Beautiful.
BEN ILGEBODU: Nice NPX call, too. Sweet. We need to name it we need to change the name of it. We just created an app called "my app."
JASON LENGSTORF: Does this work in Create React App?
BEN ILGEBODU: I can't remember, actually. We'll find out in a second.
JASON LENGSTORF: Let's roll the dice and see what happens. Is it going to yell at us?
(Laughter). Looks like it's working. Creating a new React app. Yep. Yep.
BEN ILGEBODU: So, there we have it.
JASON LENGSTORF: Very cool. Okay. So, we are getting in. It's installing whatever we need. I see React scripts, TypeScript utils. Okay. So, let's
So, I have to apologize, chat. The boop overlay is broken. I'm in the process of rebuilding the overlays for my stream. And, they will they will be much better soon. I've been kind of pushing on the Jamstack Conf, which ended this week, so I have time for side projects.
So, this is what we just set up here. We've got our "Git Ignore." I'm going to get "init" here and open it again so that VS Code picks up the right "Git Ignore." We've got a package JSON. Types, that feels very TypeScripty and we've got TypeScript, itself. Okay. I see ".tsx."
BEN ILGEBODU: Your React components have to end in ".tsx."
JASON LENGSTORF: Got it. Okay. I guess being explicit is not the worst thing in the world. (Laughter). Okay. So, what what should we look at, first? Like, do you want to walk through what's in here? Do you want to just showing some code? What's the right way to onboard, you think?
BEN ILGEBODU: We can start the app, right. So, you're using Yarn, I'm assuming. So, "yarn start" and we can see the React logo spinning there. That's just a nice getting started. And if that I mean, when that, not "if that" all works, we can take a look at the app.tsx, like it says, and, you know, you can see what basic TypeScript looks like.
JASON LENGSTORF: Yeah. Let's do it. I'm going to take this, over here. And this, over here. Let's open up. Oh, that is definitely not the button I meant to push. So, here's our app.tsx.
BEN ILGEBODU: Yep.
JASON LENGSTORF: And so, do you get that all the time, that warning now? I don't know what happened. Something got updated and now it's broken.
BEN ILGEBODU: I get that all the time in VS Code. I have to accept ESLint all the time.
So, here is our React component and TypeScript. There aren't actually any types going on in here because we just have the component and it's returning JSX here. If we wanted to, for instance, let's say we wanted to make a link component and take out that "a" tag and put it in its own component, that's when things can get interesting.
JASON LENGSTORF: Yeah, let's do it. We'll create a link component.
BEN ILGEBODU: And we'll pass in the URL and the content. How about that?
JASON LENGSTORF: Okay. So, do you have a preference? Like, here, this is defined as a function. That seems to make sense for me. I see people declare as constants. And I also see, here, it does the export default at the bottom. I've seen this. That's what I've started doing. What's what do you prefer?
BEN ILGEBODU: That's my preference. In React, there's so many different ways to do everything. So, I prefer const arrow functions. I can't really defend the reason why, but that's what I like doing. Maybe because you can have implicit returns, but, anyway, that's the form I like. But the problem is, with that form, I can't do export default with the name of the arrow function.
JASON LENGSTORF: That is true. Okay.
BEN ILGEBODU: That's always the argument against it, but, you know
JASON LENGSTORF: I've written what I would have done as a regular React component. It's got a name, that's the name of the component. It's going to take a URL prop and a content prop and use the URL as the HREF. Is there any is there anything else we want to do here?
BEN ILGEBODU: So, I'm seeing a squiggly under the link. Can you hover over that? Is that telling us anything interesting?
JASON LENGSTORF: You know what? I'm wondering if my let me open this in my non I have, like, a different VS Code profile that is significantly muted.
BEN ILGEBODU: You definitely want these helper things.
JASON LENGSTORF: Yes, I will allow it. Please!
(Laughter). All right. Let's try that again. So, I'm going to do a link and that is going to have URL and I guess maybe we want children instead of content so we can use it as a regular okay. So, then we'll return "a" HREF URL and the children. And down here, we'd use that link
BEN ILGEBODU: Let's go ahead and put those class names inside of the "A" tag. We'll put the target inside of the "A" tag. Class name, rel, we can make it configureable later, if we choose. We'll pass in the URL. That's the only part that will be configureable.
JASON LENGSTORF: Okay. I'm just going to let there we go. And then autoformat should handle all that for me.
BEN ILGEBODU: Nice!
JASON LENGSTORF: This one was because I think it wasn't being used.
BEN ILGEBODU: All right. So, here, we're already getting some helpful information in TypeScript saying that the URL is an implicit "any." Same thing for children. I'll explain more what that is, as we go. Basically, the default type is "any." That means you didn't add any types. That's what Java is, is "any." There are
JASON LENGSTORF: No rules. (Laughter).
BEN ILGEBODU: If you're going to invest in TypeScript and learn it and all this stuff, you should not support "any." Like, you should always have to have a type. No implicit "any." People say TypeScript can do some things for you, don't be so strict and such. But, I don't know. I just don't see the value in doing that and being a little bit loose. So, I always stick to it. So, that's my perception.
JASON LENGSTORF: Okay. So, then if I want to make this not "any," how do we do that in TypeScript?
BEN ILGEBODU: Yes. So, I wanted to also do, I think if you go down below and you go to your link where you're calling it, there should okay. We don't have the arrow there yet. Let's define the types for the link.
JASON LENGSTORF: Okay.
BEN ILGEBODU: So, what a so, nice thing about a React component is that it's just a function. It takes in some props and it returns some JSX, right? We can type it just like we type anything in TypeScript. So, once again, there are a couple of ways to do this, sadly. But what I use, it's called an interface TypeScript. So, above here, before the comment, I guess, you can say "interface props." So, capital "P" and then curly braces. Here's where we're going to define the types of our props. URL is a string. So, URL calling string. And once again, you can have semicolon at the end, comma at the end or nothing or new line at the end. So, how do you separate them?
JASON LENGSTORF: So, that works. This works. And this works.
BEN ILGEBODU: And that works.
JASON LENGSTORF: Chaos! Chaos!
BEN ILGEBODU: Your ESLint rule will dictate how that works. But, yes, chaos. I won't go into that.
So, then to type children, children is react.reactnode.
JASON LENGSTORF: Like this?
BEN ILGEBODU: Yes. That's what the type of children is.
JASON LENGSTORF: And so, this is a type oh, if I hover, I can see.
BEN ILGEBODU: You can see what it is.
JASON LENGSTORF: This is a type exported.
BEN ILGEBODU: You can "command+click," if you ever want to nerd out. You can see a React node is a React child or a fragment or a boolean. A React child is a React element.
JASON LENGSTORF: Click on this and we would see more. It's a rabbit hole, right? It's going to keep going down.
BEN ILGEBODU: The question is, hey, where do those types come from? Who wrote that? That's not in the React package. It's in a package called "@types/React." We saw some types that were being imported in addition to some other things?
JASON LENGSTORF: Yes, here.
BEN ILGEBODU: @types, line 11, is where that comes from. So, it's a separate thing. If your dependency isn't written in TypeScript, it needs to get TypeScript can only work if the dependencies have type definitions. So, if your dependency doesn't have it, then you have to go get it from this resource called "definitely typed."
JASON LENGSTORF: Let's find that link, "definitely typed."
BEN ILGEBODU: It's important.
JASON LENGSTORF: I should go to the.org, right?
BEN ILGEBODU: This is a repo of I don't know 5,000+ type definitions for your popular packages and probably unpopular packages. Low Dash is in here, jQuery is in here, Moment is still in here. People still use Moment. Everything you want to use is in here so you're able to have typesafe code because you want to make sure that when you call those functions, that you're passing the right types and getting back the right types.
JASON LENGSTORF: So, what about Next.js? Gatsby? [Indiscernible]. It might be written in TypeScript.
BEN ILGEBODU: It all depends.
JASON LENGSTORF: So, a lot of frameworks in here. A lot of tools. Okay. So, now that we've got access to those, here in our React Node, then
BEN ILGEBODU: But it was implicit. We got it implicitly by importing React at the top.
JASON LENGSTORF: Is that, like, a VS Code thing?
BEN ILGEBODU: That's a TypeScript thing. So, when you
JASON LENGSTORF: If I did this in Sublime or IntelliJ?
BEN ILGEBODU: To work in your editor, so you can "command+click," probably. For TypeScript to just work TypeScript works in the editor in VS Code, innately, out of the box. If you use IntelliJ, to have that integration, you're going to need plugins.
JASON LENGSTORF: Gotcha.
BEN ILGEBODU: Because you imported from React, it goes and looks to see, does React, the package, itself, have the TypeScript definitions? Oh, no, it doesn't, so let me look at "@types/react." Here's where the types are.
JASON LENGSTORF: Cool. We've written an interface. We called that interface "props" and defined our URL and our children, but I'm still getting this error. What do we have to do next?
BEN ILGEBODU: We have to tell TypeScript that the props that are being passed in, URL children, is of type props, the interface. So, after the curly brace, right there, ":Props." And we've told it those are the props.
JASON LENGSTORF: Oh! Oh, look at this! Immediately. What happens if I try to break this, then? I'm going to pass in 100.
BEN ILGEBODU: Yep.
JASON LENGSTORF: That is very cool! Okay.
BEN ILGEBODU: What if you try to remove the URL and don't pass it?
JASON LENGSTORF: That's just syntax errors.
BEN ILGEBODU: Yeah, that's a syntax error. (Laughter).
JASON LENGSTORF: "Property URL is missing."
BEN ILGEBODU: The cool thing about interfaces, as opposed to prop types, is that the properties of an interface are required by default.
JASON LENGSTORF: Okay.
BEN ILGEBODU: You have to pass them. You have to market so, like I was saying before, how people list things in their prop types but some are required, some are not, but they forget to mark the things that are required. That's a problem. Well, here in your interfaces, your properties are required by default.
JASON LENGSTORF: So what if I want to make one optional? Let's say I want to pass through this class name. I'm going to put this through here but I don't necessarily expect this one to always be used. So, I'm going to get it here actually, let's just see what happens when I add a property that's not defined.
BEN ILGEBODU: Yeah, let's do that.
JASON LENGSTORF: Does not exist on prop types.
BEN ILGEBODU: No hidden props inside your code.
JASON LENGSTORF: I like that. And this is going to be a string, I assume. I don't want to have to send it.
BEN ILGEBODU: Now, it's required. So if you do remove it uhoh, you're not passing class name. Can we take a second to see, like, all of this VS Code inline tool tips are amazing. We haven't even yet gone to the browser for it to tell us this information. If you saved and went to the browser, it's going to tell you that error, that you can't do that. If, you know, the app was running and such. (Laughter). But, uh, we are able to see all of these type information, like, as we develop. So, we're getting instant feedback without even having to go to the browser at all, which is, like, amazing.
JASON LENGSTORF: Uhhuh. This is really, really nice. This is disheartening, right? If you're working in the browser and you make a code change and you don't know that code change is wrong and you see these big, red errors, that's a bummer. This, I typed a thing and now it's mad at me and I don't have to change context, that makes this a little more approachable, I think.
BEN ILGEBODU: That's why I think it's worth it. You still have to learn some things, especially as you get more complicated. But I think it's worth it because of that.
JASON LENGSTORF: Yeah. So, there's a question, here, that I'm not even sure what like, how we would approach this because I don't know anything about this. Can you talk about the differences of types and interfaces and which ones should be used to define props and maybe you can tell me what, like, that means?
BEN ILGEBODU: So, let's do the class name.
JASON LENGSTORF: Yes, yes. Finish your thought.
BEN ILGEBODU: Then we can switch to that. So, if we wanted to make class name optional, we again, there's multiple ways to do this. (Laughter). But the canonical way is after class name, before the colon, you put a question mark. Yes. Right there, on Line 8.
JASON LENGSTORF: Okay.
BEN ILGEBODU: So what that ends up saying is the type is "string or undefined." If you hover or class name, it'll tell you. If you do it on Line 12, it'll tell you that, string or undefined.
JASON LENGSTORF: Line 12. Line 12.
BEN ILGEBODU: Yeah, in the definition. Same inside. So, that's a way to make it optional. So
JASON LENGSTORF: I could save?
BEN ILGEBODU: Everything is good. You have to pass it in.
JASON LENGSTORF: What was that?
BEN ILGEBODU: I don't remember.
JASON LENGSTORF: App link.
BEN ILGEBODU: App link.
Hey, what happens if you forget and you do "class" instead of "class name"? Another thing it tells you.
JASON LENGSTORF: Oohhh! Property class, intrinsic attributes or props. Did you mean class name? I like how they tell you how to fix your problems in your report.
BEN ILGEBODU: So these errors can be a little interestingly, right? Because there's all this information in it. Can you remove the class name part or, just the name part and just have "class"? What I like to do when I'm reading the errors is I try to read bottom to top. All right. So, I read so, I'll read property class does not exist on type intrinsic attributes. Did you mean class name? And, I'll start with there. I'm like, okay, that's enough information for me to actually understand what's going on. If there was a case where that wasn't enough we may see this case then we'll go higher and see type, children, blah, blah, blah, is not a type. Reading, bottom to top, I find is much more helpful.
JASON LENGSTORF: That's a pro tip.
BEN ILGEBODU: Pro tip!
JASON LENGSTORF: We'll call this "class name" so we stop getting those squigglies. Interfaces versus type, I would have said, this is a type. So, is there a difference?
BEN ILGEBODU: Yes. So, the question is let's add a new line. The other way to define this is type, then space, props. Let's give it a different name. Link props. There you go. I like that. And then we can copy the contents of that in there.
JASON LENGSTORF: Okay.
BEN ILGEBODU: Except it needs to be "type links props equals." This is another way to define it. Actually, the name you gave is, like, the other common way I see of naming the props for a component, is "component name props."
JASON LENGSTORF: Okay. So, if I do this
BEN ILGEBODU: Everything works the same.
JASON LENGSTORF: Same general outcome.
BEN ILGEBODU: Yes.
JASON LENGSTORF: Okay.
BEN ILGEBODU: So, the difference for 95% of the cases maybe even 99% of the cases is exactly there's no difference. This is exactly the same, just another way to do things. Right. The the the actual difference and if you try to read the docs that explain it, it's, like, so convoluted. The actual difference is when you define it as a type, it gets the the definition of the type is the object. So, it passes around that object, everywhere that you've declared a links prop. Whereas if you use interface, the definition is "props," which is a reference to the object. So, anywhere you see it, it'll actually be declaring the type as "props" itself. If that like, I don't know if that makes sense. It's really it only comes into play, like, in certain places when you are referencing this this type in, like, a parent that's using this component. It's really convoluted.
So, um, interfaces so, both of these things can be extended in certain ways. There's, like, different ways to extend the prop. So, if you wanted to declare props and add some more properties, create, you know, a new interface that had more properties to it, there are ways to do that, as well, just different syntax. So, like, really it's, like, choose your choose which one you want.
So, I always use interfaces. I always get this question from people who have used it. It's really, really negligible the difference. Generally, it doesn't matter. I have run into cases where it did matter and I had to use types. There were some situations where interfaces didn't work. However, I like defining them as interfaces just because of the syntax around extending and defining, um, that way.
JASON LENGSTORF: Nice. And I just saw [Indiscernible] you're still on the TypeScript team, right? [Indiscernible] just dropped a link to the differences between typefaces and interfaces.
BEN ILGEBODU: This used to be a twosentence explanation. Now, there's, like, way more explanation, so this is great.
JASON LENGSTORF: Nice. Nice, nice.
BEN ILGEBODU: Thank you very much.
JASON LENGSTORF: We'll make sure this ends up in the show notes, as well. It's been linked in the chat. This is all starting to click to me and I'm starting to see the benefits of why this is useful because what I want to show is usually where I start to, like, notice when things don't have typings. If I come out here and I'm like...create link.tsx. I'm going to drop all this in here and I need to import React from React. Okay. So, then
BEN ILGEBODU: Export default link. Yeah.
JASON LENGSTORF: Link. All right. Now, I'm going to come out here and let's import link from link and okay. So, now, we've got this link, but, like, I don't know how to use it. So, if I if I take this one out, right? I'm going to come here I'm going to use my link. Now what do I do? Hey, look at this? Look at this beautiful definition, right in line with how to use this thing. It'll show me that I need things. Like, that is really cool. I need stuff. (Laughter). So, all right. I need URL and children. So, if I start typing I think, right, I can even or maybe that's not going to work for me. If I come in here what's the isn't there a command? As I start
BEN ILGEBODU: Yeah, you start type. You see the list up there. Right there. Those are the properties that you can specify.
JASON LENGSTORF: These are the things we can put on this. That is just so slick.
BEN ILGEBODU: They're types, too.
JASON LENGSTORF: Yeah. Like, how slick is that, that that just works?
BEN ILGEBODU: You can do something additional cool. If you go into the link component, let's add a a variant prop, right. And
JASON LENGSTORF: Variant. Okay.
BEN ILGEBODU: So, we'll call the variant what? Regular so, put the string regular and then a pipe and the string dark. I don't go. Just as two options. So, this is a this is a no. Yes, this is a union of two values. So, we can say variant could regular or variant could be dark, the string. So, um, let's make it yeah, let's pass it in. We're not really putting it anywhere, but that's fine. Now if you go back into app.tsx and you start typing in "variant."
JASON LENGSTORF: Oh, cool!
BEN ILGEBODU: It'll tell you, these are the only two variants you can pass into it. The integration in to VS Code is amazing.
JASON LENGSTORF: That is extremely cool that that worked. We're missing our variant.
BEN ILGEBODU: You're missing your variant, pass it in.
BEN ILGEBODU: Yep. Exactly. Yeah. It's just self it's like what I was saying again, writing docs versus tooling. And, TypeScript is tooling. It forces all that stuff. Gives you all the documentation, for the most part. Whereas you don't have to write it. So, it's keeping in sync all the time.
JASON LENGSTORF: That part, too, is interesting because it gets back to the idea of you said earlier, if you write docs, either you have someone whose job it is to keep those docs uptodate or you have docs that steadily get outofdate. It's really nice to know by writing your application, you're communicating clearly about how it's supposed to be used.
BEN ILGEBODU: Exactly. There's something else cool I wanted to show. This isn't specifically React, but it comes in handy. If you go back to our link component and we had one of them that was optional. Class name.
JASON LENGSTORF: Yes.
BEN ILGEBODU: Let's say inside of the component class name, we wanted to let's declare a boolean this actually will be good. Let's declare a variable above Line 19, that's, like, "has" or "is." What class name are we passing in?
JASON LENGSTORF: We're passing in, like, app link.
BEN ILGEBODU: How about "has hyphen." If we were going to do that, we would say "classname.includes." This already was awesome. It autocompleted that because it knows.
JASON LENGSTORF: Whoa! Whoa! Whoa!
BEN ILGEBODU: I'm telling you, it knows class name as a string so it knows all the methods that strings have.
JASON LENGSTORF: Oh, dang!
BEN ILGEBODU: You skipped over the fact that it showed "includes" for you. Then, it knows that class name is "can be undefined." This is all the things that strings have. Is it includes? Is it contains? I can't remember.
JASON LENGSTORF: It's already got this null check in here.
BEN ILGEBODU: Yep, it's already got that because it knows that class time is undefined. It saved you from your eventual. "undefined is not defined."
JASON LENGSTORF: That is one of those things we would, of course knowing me, I would have written "this can never fail." (Laughter). I mean, we've all seen that comment when we're bughunting. "This is impossible" and it's inevitably the thing that takes down production. (Laughter).
BEN ILGEBODU: And then now, uh, "has" is already typed as a boolean or undefined.
JASON LENGSTORF: Okay.
BEN ILGEBODU: So, we didn't actually have to type or provide a type for what at "has"is. It's an inference that tells us that "has"is a boolean or undefined.
JASON LENGSTORF: Is it smart enough that if was to do something like this, would it
BEN ILGEBODU: Guess what? It's a boolean now.
JASON LENGSTORF: Oh, my god! I'm switching everything to TypeScript tomorrow. (Laughter).
BEN ILGEBODU: I forget what the term is for this, but it knows that once you do a check, that within that check, the existence check, within that, it knows what the type is. You have proven to it that it cannot be undefined.
JASON LENGSTORF: That is supercool! Man, that is wild. Okay. So, I mean, I I I'll be honest, I've been Lukewarm on TypeScript for one very particular reason, when you kind of addressed right off the bat, which is when you have something like TypeScript, when you get frustrated, you immediately escape to "any." Why bother? That, to me, has kind I've also seen people go through some pretty intense gymnastics to write types and it seems like they're playing, like, the type golf game as opposed to shipping code.
BEN ILGEBODU: Yes, yes.
JASON LENGSTORF: Those have always been my major pushbacks, right? But what I'm seeing here is if we're thoughtful about how we write stuff and if we put things in, especially things we're shipping to other developers any code we're shipping to other develops, the speed gains we're going to get, through the code catching these errors before I even hit my browser, even before I do local development, right, I can write this code without a dev server running and I'll still catch a lot of these errors way before I save the file. That, to me, that's enough of a speed boost to make up for the initial slowdown of having to write these types.
JASON LENGSTORF: Yeah. Yeah, yeah, yeah. I mean, this is really, really nice. Also, quick shoutout, thank you, [Indiscernible], for the sub. Seven months, that's amazing. Cassidy's going to be unhappy about this. That is untrue. Cassidy has been Lukewarm on TypeScript. If she watches this, I think she might turn around.
BEN ILGEBODU: You might send her the video.
BEN ILGEBODU: I think so. I totally agree.
JASON LENGSTORF: Excellent. So, what if we do find ourselves in a complex situation, right? A situation I find myself in is, for example, I have let's say I have a component, maybe what we can do is just create a new component. And we can talk through what I would find myself doing. So, let's say this is a complicated (Laughter). Screen generator. Right. And so, what this thing is going to do is, this is going to take a few things and turn them into, like, a URL. In a way that I ran into this this is a realworld use case are you familiar with Cloudinary?
BEN ILGEBODU: Yeah, I just used it, thanks to you.
JASON LENGSTORF: Yeah, you just did the social cards. I think that tweet is up close to the top.
BEN ILGEBODU: It should be closeish.
JASON LENGSTORF: These are autogenerated and they're using Cloudinary. So, to generate a Cloudinary link, you have to, like, add in all these settings. There's text, there's sizes. There's all this stuff. So what I found myself doing was I would have this, like, config object and in my config object, I'm doing something like, I've got we'll say, you know, width and height and, um, I can't spell today. Height. And then we would have, let's say, like, crop type. Then you've got some other things. You've got your text, right. And in your text, you've got, you know, the font family. We'll just make this family, size and weight. And that's probably complex enough. As you can see, this would get more complex as it goes. So you end up with these pretty complex types here. So, if I wanted to write this, I feel like I wouldn't be able maybe I can. So, if I just come up here and go "interface," and then I would say "complex config." And then I get my width and that one's going to be
BEN ILGEBODU: A number.
JASON LENGSTORF: Number. Height would also be a number.
BEN ILGEBODU: Number, yeah.
JASON LENGSTORF: Crop, we can say "fill" or "thumb" or something like that. And then my font I can't do this, right?
BEN ILGEBODU: You can do that.
JASON LENGSTORF: I can do that?
BEN ILGEBODU: That's a type alias. It doesn't have a name, but that's just, like, an inline type.
JASON LENGSTORF: Okay. What if I want to do a range? So, I have
BEN ILGEBODU: Ahhhh.
JASON LENGSTORF: A font weight can be any number, 100 to 900.
BEN ILGEBODU: 100 to 900. Okay. I don't think there is a utility for that. But let's check. So, if you type or search for TypeScript Utilities...[Indiscernible] is telling us it's a mapped type.
JASON LENGSTORF: Other props in the same interface, to optional or required? So, that's if we added
BEN ILGEBODU: The last one. He's talking about something else.
JASON LENGSTORF: Yeah, he's talking about something else, which would be interesting because instead of a width and height, we provide an aspect ratio.
BEN ILGEBODU: These are some helpful types. If you but I'm not sure if range is in there. I haven't ever seen range. So, obviously, you could the (Laughter). The sort of it
JASON LENGSTORF: [Indiscernible] was not listening, but he is now. We're trying to figure out how we could do a range. If I had a variable font, I can enter any value let's say this has 100 to 900. A range primitive?
BEN ILGEBODU: I don't think there is
JASON LENGSTORF: No range primitive.
BEN ILGEBODU: No lowdash range. The worstcase scenario is to use 100 pipe, 101 pipe and that would work. (Laughter). But you could you could kind of yeah. For it to verify
JASON LENGSTORF: I mean, it's not wait, would that how does that hold on. He's showing us something. So
BEN ILGEBODU: If you defined it this way, then you would have your code verify that it's between those two numbers.
JASON LENGSTORF: I'm doing something wrong.
BEN ILGEBODU: So, um, it's a tuple. If you do well, there's a utility type for Tuple, I believe. If you wanted to define an array of two numbers, you don't need to name them. You could just say "number number," that way. You pass in the bottom number and the top number and then you would verify that it's between those two numbers that are passed in. You're not really saying 100 or 900.
JASON LENGSTORF: Okay. I understand. And that's okay. So for this particular case, we could probably just do, like, you know
BEN ILGEBODU: If it was like that, then it could be between them. But, I think these are the type of things that TypeScript is adding in newer versions. Even since I've been using it over the past two years, I've seen more of these types of helpers to solve these types of problems.
JASON LENGSTORF: Gotcha. This is not really that big of a deal, right. If I go in and I set it as a number, then I can immediately say, like, if, you know, weight is greater than or less than 100, or greater than 900, you know, there's a problem. So, like, I can still write logic so we don't need TypeScript to solve all of our problems. It won't catch it immediately for us.
BEN ILGEBODU: Right. Yeah. It would be nice if that was prevented, that you couldn't pass in zero. As far as I know, that's not possible yet.
JASON LENGSTORF: Yeah. This would be fine for standard font weights, but it wouldn't work for variable font weights.
So, this is actually new to me. I thought that you couldn't do this.
BEN ILGEBODU: Yeah, you can do it.
JASON LENGSTORF: So that's actually really interesting. What I'd be able to do down here, then, is say "complex config"?
BEN ILGEBODU: You const config:
JASON LENGSTORF: I would need to actually set these in here and this should autofill and it does. We can set our family
BEN ILGEBODU: You just glossed over the fact that that autocompleted for you.
JASON LENGSTORF: It happened so fast. It feels so natural when it's working. This is really powerful stuff because the thing I think is really interesting about this, if we have let's assume this was actually going to return something. We'll have a const link and it it's going to take it's going to take this complex config.
BEN ILGEBODU: Uhhuh.
JASON LENGSTORF: So I can drop that in there and what that's going to return for us, for now, probably can I do this?
BEN ILGEBODU: Yep, you can do that.
JASON LENGSTORF: We can just return, for the sake of debugging, just JSON string [Indiscernible] props.
BEN ILGEBODU: Uhhuh.
JASON LENGSTORF: And then export default. Link gen. And so now, doesn't like what? Oh, React must be [Away from mic]. That makes sense.
BEN ILGEBODU: There we go.
JASON LENGSTORF: So now, I can we can get rid of this one.
BEN ILGEBODU: Uhhuh.
JASON LENGSTORF: And my props are here so when I come out here and I try to use this...
BEN ILGEBODU: Complicated. Complicated. [Away from mic].
JASON LENGSTORF: Call it "complicated"? I think I named this very poorly. I named it "link gen." Jeez! I did this all wrong. (Laughter). Oohhh. Okay. Please don't judge my naming. (Laughter).
BEN ILGEBODU: This is a livestream, okay?
JASON LENGSTORF: So I've got my link gen, and in here, if I hit "control+space," I get all of my my so I'm going to do my prop. Right. And then this one, it's autocompleting for me.
BEN ILGEBODU: Fill.
JASON LENGSTORF: What if I do my font? How does that work? Like, is this going oohhhh! Look at it go! Oh, my God! That is amazing! All right. So then if I try to put in the wrong value, it's going to say, no, that's a string. You got to make that a string.
BEN ILGEBODU: Yeah, you got to make that a string.
JASON LENGSTORF: Ohhh, look at that, too. As I do that, it pulls out the values. It's telling me I have size and weight left and the size is 100 so now it's showing me weight. Hot damn!
BEN ILGEBODU: I don't know if you left the "..." inside of the definition?
JASON LENGSTORF: I don't think I did. I think I pulled those out. I've got my height and my width. What was left? No key. Check this out! Now if I go back and I look, there's our object. And without having to go look at that component, to figure out what I had said we did a lot here. There's no way that I would have been able to remember all of these props, had I not just had autocomplete.
BEN ILGEBODU: Exactly. So, you can, though, add JSDoc to this. If you go back to "complicatedstring.generate.jsdoc," JSDoc is what I use. You say "/**." You can give a definition of what "width" is. It's a string. Perfect. So now we go back to our app and you hover over width and it tells you, there, the width of the image.
JASON LENGSTORF: This is like, this is amazing, right? I feel like this is what I always want comments to be. I know myself, right. And I know that I am probably you know in the grand scheme of people who are willing to open up Node modules and dive in and look at what's going on in there, I'm probably in the minority of developers who get excited about that. I'm like, ohhh, let's go find out how that thing works. I still never, ever, ever see these types of comments unless I've hit a headscratcher of a bug. Being able to surface those comments to me, in context, is that is legit.
BEN ILGEBODU: When you're building something that other people have to use, this sort of thing is invaluable. Link gen is so much easier to use because you've added that in there.
JASON LENGSTORF: Yeah. Okay. So, one thing we haven't talked about, that might be worth mentioning, is what would we do if we had a default value? If I know my font family is going to be, like, Arial by default?
BEN ILGEBODU: Go into "complicated string generator." In prop types, it's.deprops. You add that to your component and say ".defaultprops." This would have been Linkgen.prop
JASON LENGSTORF: I haven't done this in so long. I always end up doing it in the prop themselves, the ES6 prop name equals value.
BEN ILGEBODU: That's basically how you do it. What you're saying is how you do it. You would put it in here, in the ES6 definition. We'd have to break it out.
JASON LENGSTORF: And that's fine. So we can take all of this and we'll just
BEN ILGEBODU: Do stuff.
JASON LENGSTORF: Take these out. Turn those into commas. Font. Here. Take these two out, as well.
BEN ILGEBODU: Yeah, if you wanted those all to be individual values.
JASON LENGSTORF: And then this would be Arial. Unfortunately, I have to do that because I picked the hardest one to default. (Laughter). Then, we take all of these. We can copy those and just drop them in here. And...oh dang it. Family size. All right. So, now what I've got is, we're still using the complex config so we know the types of these, right. They're all figured out here.
BEN ILGEBODU: Yep.
JASON LENGSTORF: So you're saying now if I go out here, it should just tell me?
BEN ILGEBODU: Uh, yeah. Obviously, if you don't it will default it for you. If you go to if you hover over "font," let's see...actually, I'm trying to think if it will tell you. Oh, well, we didn't we need to make "font," "family," optional up top, in our definition there. Make it optional there. Let's see what it will tell us. It doesn't tell us what the value is. Okay.
JASON LENGSTORF: Do we have to, like, doubledeclare it? Do I have to put it in here or something?
BEN ILGEBODU: No, you don't have to do that.
JASON LENGSTORF: No, it doesn't like that. It hates that. (Laughter).
BEN ILGEBODU: It will default it in the code for you. I know there's one way you can also use JSDoc to tell you what it is. Then you'd have to doubledeclare it. So, it doesn't pick it up at least it's not seeming like it picks it up from the code.
JASON LENGSTORF: JSDoc.default. We'd do "@defaultarial."
BEN ILGEBODU: Yeah. When you're typing in "family," there you go.
JASON LENGSTORF: And then it just works. There's our default family, despite not having a family declared. I mean, that's slick. I'm into this.
And, like, if that's the most complicated thing we have to do, is pull out defaults to be autocompleted for us, that's pretty awesome.
BEN ILGEBODU: For communication to others, yeah.
JASON LENGSTORF: Yeah. And really, like, some of this stuff is important to communicate. Like, this one, maybe not as important to communicate. Because, a default is a default. If you're building a component system, the last thing you want is someone changing the font family. That's how you end up with Comic Sans. (Laughter).
BEN ILGEBODU: Yes, exactly. (Laughter).
JASON LENGSTORF: Like, I feel like this is really good, because it these are the sorts of things that I think are hard to get right through strict communication. Like, persontoperson communication. And this goes back to what you were saying, earlier, about tooling over docs.
BEN ILGEBODU: Right. Yeah.
JASON LENGSTORF: When you first said that, I was ready to raise an eye brow at you.
BEN ILGEBODU: People continually raise eyebrows when I say that. I love docs, React docs that explain how it works. But the kind of these sorts of things, I prefer tooling.
JASON LENGSTORF: Yeah. Yeah. Well, dang. And this is really cool. I'm going to make this slightlyeasier to read, just by adding a text align left.
BEN ILGEBODU: I was wondering what was going on. (Laughter).
JASON LENGSTORF: I love the oh, [Indiscernible] is saying "types for tooling." I think that encompasses my thoughts around this, too. I think if I was to bundle up my emerging philosophy on TypeScript, I have shipped a couple NPM packages where it's not written in TypeScript, but I export a type so I get the autocomplete. It's sort of like a middle sort of there. What I'm starting to get toward what I'm starting to feel, especially after seeing this, TypeScript is the most useful when it's the code under the code. The DivOps stuff you're talking about or if you're building component libraries or shared resources. I think if I was if I'm working on my personal site and it's a component that doesn't get shared, I'm really writing components because they're in React, I care slightly less about it because the same code's in the file. I can already see what you're (Laughter).
BEN ILGEBODU: We indexed on, like, the props and communication between things, like, that's where TypeScript shines the most, for sure. At least in terms of React. But, things like what we saw with class name
JASON LENGSTORF: Where it picked up the class versus class name?
BEN ILGEBODU: Yes no. Can you go back to that link? Includes. The classname.includes. Those sorts of things, TypeScript really helps as well, even though it's your internal thing. We focused a lot on the props, for sure. But there are other aspects of it, too, that we could get into when we start talking about hooks and how those things work and how it helps with those, so
JASON LENGSTORF: We're a little short on time. We've got maybe 12 minutes. Do we have time to look at a hook? Because that would actually be interesting.
BEN ILGEBODU: Sure. We could do something with [Indiscernible].
JASON LENGSTORF: Okay. Cool. Let's do it. Let's just drop in a new component and we'll do a countercomponent. That's one I know we can build quickly. So, we import React from React. And then we can, um, export default, function, counter and that's going to take in whatever props it takes in. We can leave that blank for now and it's going to return let's do a button. And, we can just do, like, a clicked we'll hardcode it for now.
BEN ILGEBODU: Uhhuh.
JASON LENGSTORF: So that's the structure of our button and then we'll go in actually, you know what? So that we can see the interface work, why don't we I guess we're not going to do that really. We're going to be doing that with the thing itself so let's get the counter in here.
BEN ILGEBODU: Yep.
JASON LENGSTORF: This would be counter, I think. Did I do it as a default or not? Default.
BEN ILGEBODU: In the chat, I'm seeing someone in the chat share out the TypeScript cheat sheet for React. It's amazing. It has, like it has all of these kind of recipes for solving different problems in React. So, it shows how to do various different stuff with props. This prop can only exist when this other prop has been defined, like, those sort of interesting situations, but, just give a double shoutout for that.
JASON LENGSTORF: So I'm going to drop a count in here and when we look at this, we've got our "click zero time." I'm going to do "increment." And that'll be "set count."
BEN ILGEBODU: "Set count."
JASON LENGSTORF: State would be "count+1." "Onclick=increment." There we go. We have a basic counter in place. So, to TypeScriptify this
BEN ILGEBODU: You don't have to do anything.
JASON LENGSTORF: What?!?
BEN ILGEBODU: It's already typesafe.
JASON LENGSTORF: I feel like I was hornswoggled just now. It inferred everything. Like, that's cool
BEN ILGEBODU: That's the return value of "set count" is void.
JASON LENGSTORF: It pulled that across to "void" is really slick.
BEN ILGEBODU: So what's happening is the use state, you're passing zero. So then it infers that, okay, the state you must want is zero. Or a number, rather. So that is what "count" is. "Set count" takes in a number. It knows "count" is zero. If you do a string operation on "count," it wouldn't work. It's going to complain.
JASON LENGSTORF: Wow! Okay. All right.
BEN ILGEBODU: Where this actually becomes most helpful because you know how sometimes we pass this, like, set count to another component that we've defined? Right. And it's going to do whatever option. So, when that component does its "onblank" event, it's going to call this function. Well, we ensure that those functions are the right types so we know that, yes, this is going to be called with a string, only one string value and it's not returning anything. We get to have that type safety. If that component decided to change its interface and switch from a number to a string or add two arguments, all of a sudden, things would break. So, we can get in to that situation and see how
JASON LENGSTORF: To get us into that situation immediately, I moved the use state up a level and now we're passing values into "counter"?
BEN ILGEBODU: Yep.
JASON LENGSTORF: So, this is giving me it's complaining at me.
BEN ILGEBODU: Because you haven't defined what those are. Oh, bam! We missed my most favorite part of TypeScript! Let's define our interface. Interface props for counter.
JASON LENGSTORF: Interface props.
BEN ILGEBODU: We have to define the increment function. Increment is a function, right? So it's a function that is what is it? It's going to be called with nothing? With the new value?
JASON LENGSTORF: It's currently called with nothing.
BEN ILGEBODU: So then we will define you just pass in "empty parenthesis" and "arrow" and then "void." That's the definition of "increment." As opposed to React prop types, you actually get to specify what the arguments and returned value of your function are. Which is cool.
JASON LENGSTORF: Cool!
BEN ILGEBODU: So, let's so, yeah. So, now this is perfectly typesafe. If you go back into app, we're now saying that the increment function we're passing to it, it has to be empty parameters and return void
JASON LENGSTORF: If I were to do something like take the count and return array, it's immediately, like...
BEN ILGEBODU: Well, we have to define what so, yeah, you have to define what
JASON LENGSTORF: Let me know this incorrectly, properly. (Laughter). Okay. So, this implicitly has an "any" and that's because, I assume
BEN ILGEBODU: Because you are you are what's the word? Providing a new variable called "count" for this. Not using that variable count, because you're making it the argument of the function.
JASON LENGSTORF: Oohhhhh! Oh, oh!
BEN ILGEBODU: What's the word?
JASON LENGSTORF: Are declaring it? Out of scope.
BEN ILGEBODU: You have to provide a type for "other." Let's say "other" is a string.
JASON LENGSTORF: And now it's mad at me. Oh, because it picked up that "other" string returns a string and it says, no.
BEN ILGEBODU: No, that's not what "increment" does. "Increment" doesn't take any arguments.
JASON LENGSTORF: I guess it's still mad about this.
BEN ILGEBODU: Okay.
JASON LENGSTORF: Once I fixed that error, it's like, no, you can't do that, either.
BEN ILGEBODU: What if we switched things up inside of" counter" and had the increment function pass you the new value of "count?"
JASON LENGSTORF: So, we want to return a number then?
BEN ILGEBODU: Not, not return a number. It's called with a number.
JASON LENGSTORF: Okay. We want to pass in "count" like this?
BEN ILGEBODU: Now inside the implementation of "counter," we're going to define what should we call it? Let's rename "increment" to I don't know, "on increment," maybe? It's saying "on click doesn't take a number as its parameter." So the way you're doing it is already incorrect. So, it's already it's helping us out. So, let's create a function enter function inside of here, that will call "increment." Handle click. Perfect.
JASON LENGSTORF: Something like that?
BEN ILGEBODU: Increment with count, plus one.
JASON LENGSTORF: Handle click. And this is going to be "count+1."
BEN ILGEBODU: So now we're calling increment with the new value. So, now back here, our increment function is incorrect or
JASON LENGSTORF: It says
JASON LENGSTORF: Right.
BEN ILGEBODU: If you go back to "app" right now, with our "Increment" function, we're effectively choosing not to use the value being passed to us, which was "new count."
JASON LENGSTORF: Right.
BEN ILGEBODU: That's why we're not getting an error.
JASON LENGSTORF: Oh, I need to make that new "count."
BEN ILGEBODU: What you name it here doesn't really matter. It could be anything inside of there.
So let's go back to "app." So now our "increment" function, on Line 11, takes new count with set count there. And "new count," we have to tell it it's a number.
JASON LENGSTORF: Okay.
BEN ILGEBODU: So now our code works correctly. However, we could just pass "set count" directly to "increment. "We know we should be able to do that.
JASON LENGSTORF: We can do it straight like this.
BEN ILGEBODU: Yes. Everything compiles correctly because it takes a number and returns void and that's what we're passing to it. So everything still typechecks correctly.
JASON LENGSTORF: That's pretty slick. We also know now, anything we're trying to do here, even if we didn't get the result we wanted, it's not because we wrote the code improperly. We've moved away to whether we've gotten the language right to whether we've gotten the logic right. If you have watched somebody knew to a language or musical instrument or spoken language, there's so much cognitive overhead that goes into just making sure we're doing it correctly. If you watch me dance, you're not watching me dance, you're watching me try to remember if I'm moving my foot to the right place. I'll spend so much energy thinking about how to do the thing that I really don't have time to determine whether or not I'm doing it properly.
And so I think that one thing that TypeScript is giving us, is it's making sure we don't have to wonder if we're doing the language wrong or our logic wrong. It takes that out of the equation.
BEN ILGEBODU: That's a good way to put it. I like that.
JASON LENGSTORF: Let's see me dance. Let's not see me dance. (Laughter). Unfortunately, that's all the time we have. Ben, where should people go if they want to take nextsteps, followup with you?
BEN ILGEBODU: I've got two places to send folks and then I've got a special giveaway, if that's cool.
JASON LENGSTORF: Oh, dang, yeah.
BEN ILGEBODU: Twitter is the best way for quick communication. I think you had it up there already. You can go there. I tweet about things. I tweet about tech. I tweet about basketball, as well, a lot. Although that may die down because the NBA finals are almost over. But, I tweet about lots of different things because I'm a person.
And the other place is my website, so, benmvp.com. And, there, I have a blog, where I talk about that's all tech. My site is all about tech and things like that. And, list of the speaking engagements I have, videos there. You can read those up top. But what I want to mention is the minishops there. So, if you click on that, in the topleft. Those are short workshops I host every once in awhile. So they are minishops because they're mini workshops. So, as you can see here, I have a number of them. One being TypeScript For React Developers. So, it kind of goes into more detail as to what we are just you know talking about right now. It's coming up at the end of October for those who are interested.
And handson workshop and stuff like that. So, what I want to do, for your livestreamers, anybody who's interested in this workshop, I'm going to give away one free spot to
JASON LENGSTORF: How do we get it?
BEN ILGEBODU: If you can share the link on Twitter. Please @ me. Share the link on Twitter and I'll pick one person to giveaway a free seat.
JASON LENGSTORF: That is this link, here. Share that link. Tag benmvp and you might be the lucky winner and if you're not the lucky winner, go anyways.
BEN ILGEBODU: Bonus points if you can share a selfie of you and the livestream.
JASON LENGSTORF: We are out of time. Ben, thank you so, so much for hanging out for us today. I feel like you turned the corner for me on TypeScript.
BEN ILGEBODU: I didn't even know I had to do that, but I'm glad that that worked out.
JASON LENGSTORF: Chat, thank you, as always, for hanging out with us. We've got some really fun things coming on. Natalia's going to teach us how to do Vue. Thank you, again, to our sponsors, Netlify, Fauna, Sanity and Auth0, who all kick in to make the live captioning possible. That is provided by White Coat Captioning.
And, with that, I think we're done.
BEN ILGEBODU: We're done. Awesome. This is my first livestream, ever.
JASON LENGSTORF: You nailed it. I never would have guessed.
BEN ILGEBODU: I've done live talks, live streaming.
JASON LENGSTORF: Chat, stay tuned. We're going to raid. Ben, thank you so much for your time. We'll see you next time.
BEN ILGEBODU: All righty. Bye.