Summary
rootDir (source directory) and outDir (output directory for compiled files)module setting controls how imports/exports are evaluated (NodeNext for Node.js, ES2020 for browsers, etc.)target setting specifies which JavaScript version to compile to (ES5, ES6, ES2020, ESNext, etc.)lib option defines standard libraries available (DOM for browser APIs, ES2022 for modern JavaScript features)noEmit: true makes TypeScript only check for errors without compiling filesany type - it disables type checkingunknown instead of any when type is uncertain - forces type checking before usevoid is for functions that don't return anythingnever is for functions that never return (e.g., always throw errors)noImplicitAny rule errors when TypeScript cannot infer a typeproperty?: type)string | number)alignment: "left" | "center" | "right" only allows those three string valuestype keyword to define reusable types& operatoras keyword to tell TypeScript the specific type of a value<type>value) conflicts with JSX, prefer as syntaxelement as HTMLInputElement)!) tells TypeScript a value won't be nullElement | null, requiring null checksquerySelector<HTMLInputElement>('.selector')npm create vite@latestdev (dev server), build (compile), preview (serve built files)Notes
Transcript
I have a demo that I'm going to work through that's showing taking normal JavaScript and what errors it would have when you try to convert it over to TypeScript and fixing those. And that demo is kind of a... A preview of the assignment that I put out today. So I posted an assignment that will be due before class next week. And it's, uh... We're gonna talk about it or I'm gonna show. like solutions and talk about it in class next week.
So it's... Definitely do it before class, no late submission. It shouldn't take you too long to do once you kind of get in the mix of it. And the demo we did today is kind of a similar thing, it's just different. So the document's posted. The document also has some guidance and things throughout it. It shouldn't. It shouldn't take you very long to do. But make sure you have that turned in. Before next class, and obviously if you end up with questions or anything, look it over as soon as you get a chance and ask your questions early.
I'm probably going to just plan on next week's class talking about React. Give a little bit of like the high level on React and then talk about using TypeScript with React and kind of giving us the, A little bit of aFirst week of React stuff, we're gonna spend a couple weeks looking at React and then we're gonna move on to other Stop. So. That's the plan. Like I said, I don't expect to have time. Also, I'm gonna feel great today.
So one thing we're going to see, we're going to see again using the TypeScript compiler tonight a little bit. And then after the TypeScript compiler, I'm going to show you a way to use the TypeScript compiler without actually using it to compile your TypeScript. And that's when we'll move on to looking at likeUsing to set up a little dev environment. It's a pretty popular local dev environment for JavaScriptFocused applications.
It supports all the major frameworks, including React, plain JavaScript, and it supports plain JavaScript or TypeScript, it even supports three different variants of TypeScript using different We use React with it. Reacting to my scripting. There's a React compiler with it, there's a SCMC compiler, there's a bunch of options in it and it gets configured by just a question and answer thing when you generate a project.
I know we talked a little bit about the TypeScript setup, how you need the TypeScript package.
TypeScript package installed for TypeScript compiler. If you're using code editor that's based on Visual Studio Code. TypeScript language server will be built in. If you're using another editor, you might have to install a TypeScript language server. If you're using an editor that has a TypeScript language server, you don't really have to run the TypeScript compiler to check for errors because the editor is going to be checking for it.
But the TypeScript compiler, if you don't have another build process, would still need to be there to convert the TypeScript to JavaScript. and or In your build process it would be there to run continuous integration checks. Either deploying something or pushing up the GitHub or-various different CI steps. You might want to run the TypeScript compiler just to check for errors. But usually The bigger build processes have another tool that's also doing the transcript confirmation, so you don't really need to run both.
I know I went through this really fast at the end, I'm not going to read you these from scratch, but we have these two examples that we looked at last week.
So the first one, let me just open this one for you. So the first one was the one that I just called it basic typescript. And this was a node package or a node project that we initialized.
We talked about little bit about how TypeScript will implicitly like infer types if you don't explicitly type them. So this here, the x variable is explicitly typed as a string, which means we explicitly said this will always have a string.
Or set it to undefined. It's gonna be a problem because it says "made of string" So The Y variable in this case, if we hover over it, you can see that the editor still is inferring the correct title. saying, oh, this is a string. Why is it a string? If we look down here, It says, oh, this y is a number. We'll get to why that is in a second. And then we get to this one, and it says this y is a string.
And we have a function that has some Basic primitive type annotations and then a return type annotation. So in other words, we're annotating the types on our parameters and then also the return type of the function.
The one thing that I changed a couple things in here. I want to show something with this one. But up here under file layout, comment in these lines and I adjusted the paths to basically say the root directory is source and the output directory is disk. So basically that tells the TypeScript compiler I want you to look at all the files in source and compile all the TypeScript files into equivalent JavaScript files in the disk directory.
And now when you have one of these tsconfig files, You can run the TypeScript compiler directly without anySorry. file pass to it and it will look at this config file and run it based on that. So, to look at Another thing I want to just call out real quick is Um. The module situation here, that's for how is it going to Evaluate. imports and exports and all that. Node Next is fine for these examples we're doing.
A bunch of different options here. that are allowed for module. Preserve, which will just leave it as is. NodeMex, which is what we're using. There's all these Node versions. There's Echoscript versions.
So if you put ES2020 in there, it's going to use ECOScript 2020 style of imports and exports.
But another one that you It's kind of-I don't say important, but it's what would have changed is this target Target Is what? What level of JavaScript do you want generated? So what version of JavaScript do you want the TypeScript converted to? And these are all the different options. PS Next is like... Cutting edge, newest version.
Then we have different versions of Ecloscript, all the way back to Ecloscript 3. ES5 is the old version of JavaScript before the major changes. still considered the absolute widest of the widely supported JavaScript.
And then just some other Options that be aware of is Some of this lib and types You can comment, uncomment some of these and add certain libraries. So you can say, You could say, okay, the DOM library is part of this project.
You should assume that I have access to the DOM. And then when TypeScript's looking at your source code, If you do like a document getElementById, it understands what kind of types that does because that's part of the DOM.
So the nice thing is when you generate your project, we'll set up your TypeScript config file with all the right directories and sensible defaults.
So again, we talked about all these last week, so I'm just gonna shoot through them, but basically type basic annotations for primitives. Straight number bullying, most important thing here was. We're going to annotate these as lowercase string number, not uppercase. Um... Null and undefined, any, again, I'm gonna stop here for just a second, because any is not, I know I mentioned this last week, but I wanted to just, reinforce this one of what using any at all costs This is what you would consider an explicit any.
At that point TypeScript would be looking at that as any. Anything. One of the rules that are in the default typescript setup that you're going to have to look at in your lab and also you'll see in the demo tonight One of the typescript rules is no implicit any. which basically means TypeScript will error If any of your variables are implicitly being assigned n, It will let you explicitly assign any Because it may say, okay, there's a reason you're putting any on this, so it's okay.
But a default rule that's pretty much always turned out on this development lesson because it doesn't want you to just assume that he did it. Yeah.
Unknown is the other one that I talked about last week. I'll stop here for a second. Undone is a little better. Unknown just basically means Can I just go-anything could be in this variable and don't make any assumptions of what's in it. unless I've tested it. So in this case, If you set this random value as an unknown variable or unknown type, put this number in it, and then this if statement, you say, well, is the type of random value a number?
Is it this? No. Is it not? No. So like if you have a variable that is defined to hold a string or no. or string or undefined. A lot of things, a lot of the down stuff returns on the phone. Like when you do a document get element by ID, you're going to either get an element back or a default. So that's how it's typed in TypeScript. So when you go to use that, You're going to get a message that says this variable could be undefined.
How do you deal with that? So you either have to say, like wrap it in an if statement that says, oh, if this is an instance of an element, do this, or if this is defined, do this or you can do something like if it's not defined so just looking at it and doing a not variable where it will basically say undefined the opposite of undefined right it means it is defined So if it's not defined, or on the phone, throw an error.
So you gotta just decide how do you wanna handle that. I would say, When you're doing your type narrowing and type checking to try to determine if something's undefined or not, You want to ask yourself what would happen in this application If I get to this spot and it's undefined. So you're in a normal DOM application and you're querying for an element in the page and you're going to add an event listener to it.
Okay. So you query the element. And then you go to do that element dot add a met list. Well, if that element's undefined, What do you want to happen? Because if it's undefined, That event listener will not be able to be added. So is that a critical part of your application? Do you want it to throw an error if that's not defined so that your application actually has a runtime error? Or do you want it to silently just Fail.
Maybe that's okay. But let's say it's more critical where you're querying for an element that if it doesn't exist, something's broken. You might not want that to silently fail. So that would be a case where I would probably lean towards saying, after I query for the element, do a test that says if this element doesn't exist, like if it was undefined, Throw an arrow. Because that's where Apple definitely likes to go.
I said, "Boy, there's nothing." Typically only used for functions that return not that. Typically you don't explicitly type that. Functions, we'll figure it out, or it takes, we can figure it out, because there's no return state. Um... Arrays, remember we talked about it, either syntax. I like the first syntax, but either syntax works.
Talk about e-news. We'll maybe look at that later. Um. We talked about never being something that is usually only used on a return type, typically. But it's like this function is going to throw an error, so it's never going to return.
possible for this function to return. Because it's going to always go in there. So if you could type it in the number.
So interfaces are basically the definition of an object or what an object looks like. The way that it's typically worded or you'll hear people refer to it is it's defining the shape of the object. So what does that object look like? So we're defining here a user interface That has That means that this object is an object that includes a name, an age, It includes an email that's optional.
So that's what the question mark means there.
It means that that's an optional property. And then we can also assign a read-only property that means once it's set, it can't be changed. Now what that does is if you say I have this new user variable that is of type user, because now it knows what a user is, it can start to infer that from your interface. So in this case, Name, age, and ID all match and they're required because they don't have the question mark.
It's going to automatically know how to help you and like refill stuff and say, oh, these are the properties that exist. These are the old ones. It's going to show you that behavior. I like to use interfaces anytime I'm defining a shift. We're going to see in a few Slides, other ways to define types. But if you're basically defining what an object looks like in your application,Reach for an interface.
So Union types Look. like you see here. This is saying The variable value contains a string or a number. Hey, come here. any number of other types. So these types can be Primitives. You can have an interface as a type here. This could have said value is a user or a string. Last slide, please. The union type can be any of those. Okay. And basically, it's just going to tell us it could be any of those.
Now, if we do have a variable that's doing a union type that can have multiple things, You're going to have to test So this is valid. Like, yes, I can put a number in there. But Later on when you go to use value, TypeScript's going to be like, well, it could be holding a string or a number, so you should check it for is it a instance of a number, or is it a type of a number, Or is it a string, you know, doing stuff like that to check it.
But this is a way that you can get around having variables for multiple things. Literal types is, most of the time I see it done with strings.
So a literal type is what are the exact values? I'll do that. So in this case, We're saying the variable alignment It's going to hold a string. And it's going to be a string that is either the word left, center, or right. So the other way to have typed this would have just been let alignment be a string. And then that would let us put anything. Any strength. What we're doing here is we're saying, OK, this alignment variable that we're going to use within our code Should only ever have one of these three strings in it.
So Intersection types let you combine types into a new type.
We can use the type keyword to The type keyboard is creating basically a type alias. And We can say, OK, we're going to create this new type called manager employee. And that new type should be set to The employee type. and the manager type. And this and here is the intersection type, and it basically is combining those two and creating a new type that is the combination of both of those. So if we create a new variable called manager and we say that it's typed as a manager employee, that object will need to contain all three of those properties.
The type keyword is what creates a type alias. And basically the way that works is you say type and you say what type are you creating and then you set it equal to something. We saw the intersection just on the last slide. Oh. The literal type. Previously, right, so that's basically a type. So even though this is a literal type, Well, this is literally typing the variable. This is creating a type. So like here, We've Created a variable and just inline applied alignment to it and said, or not like, applied this type of these three strings, But we could also have said,Tight alignment.
Custom typing. So like this example here, type of point is equal to an object with an X number and a Y number. That works. It also makes that an interface, right? Because it's an object. I It works either way, right? You can use types for that.
This is a union type of two other, like we're creating a new type, ID, that is a string or a number, and then we can use ID instead of string type number anywhere in our code. So these aliases help us Kind of weird. Reusability, right? It's kind of like the whole CSS idea, right? If you define a rule in one spot, you have one spot to change it. functions example we reviewed earlier today. parameters can get typed and return values can get typed.
So That's... Standard. If we have optional parameters, It's the same way we had optional properties on an interface. Just put a question mark after the name of the property before the colon and that becomes an optional parameter. We call this function, we know we can call it.
default parameters basically just works like default parameters does in a normal function we just type it so there's really nothing Here that's different?
Last week, this is that. syntax where you put three periods in a variable and any number of parameters you pass in We can combine it to an array and pass to the function as an array under that name. So the rest parameter-gets typed as an array. It's going to come into your function. So in this case you're saying The parameters to the sum function can be any number of numbers. And when they come in, it will be come in and the numbers variable will be an array of numbers.
There's also the idea of Typing or creating a type So using type alias or Just directly using the type. and saying this variable type or this type is a function. Right, so. This case here. We're declaring this variable called multiply. And inside it, we're putting an arrow function. This is like a function expression syntax, right?
It's a standard arrow function that's getting put inside multiply. So that means in our code, we could call multiply parentheses xy and run it, right? How do we type that multiply variable? Well, that variable is going to hold a function. So we have to have a function type. So... It's oftentimes nice to do this with type aliases. So we can use the type alias here and say, okay, we have a type called a math operation.
That tight is going to hold. A function signal. And you see what the function signature looks like? It's a very simple signature that just basically defines what are the parameters of the function look like and what is the function return. It doesn't care about an implementation, right? care about what's going on. It just wants to know what needs to be given to it and what is it going to give back.
Um... But there's a few different ways that we can do this. The most common uses are working with unknowns. So we might say this variable as, we're going to see this in a minute, as is one of the ways we can use it. So this variable as unknown.
So it's going to assume that it's an element. If you try to take that element, let's say you query for an input element, form the input element. and you try to say that variable.value, TypeScript's not going to let you do it. I was going to say the value property does not exist on an element. So at that point you either have to say, oh, I know I just queried for an input element. So I'm going to tell TypeScript, This variable as HTML input element so it knows that This is an HTML input and then it'll know what property.
You don't see this as much anymore and the reason is because of React and JSX.
So the parentheses does help that a little bit in this case, but-The more preferred syntax now is to use the ASK keyword. So this is the exact same thing. and say other value as a string, you still have to put it in parentheses because You can't call .length on the string type, right? So you're saying, take other value as a string, do that in parentheses, and then whatever you have there, call .length on it.
So this is the preferred syntax. Now, if at runtime, Other value is not a string? It's gonna crash. If you had an actual number in here, and you tried to call number.link, TypeScript in your editor is not going to care, because you told it it's a string. But when it runs, it's not gonna run. So that's where you have to be a little careful on the surface. But if you know it, Asserting is fine. like I said, really particular and further type narrow by using type, we're gonna see a slide on this in a minute too, but type of, instance of, a couple other options there and test it first.
TypeScript doesn't care. It's fine. It's happy. But you see what it is assuming Element is going to be right It's saying it's going to be an element or no. So there's a few ways we can go about this. So let's try the as first, just for a second. As HTML element. So We know this is an HTML element, let's say, because we know we're selecting a div. Now we hover over an element. It does say, okay, it's an HTML element, but you notice the thing that it's missing now.
Query selector is defined with generics, and the generic syntax in TSX uses angle rounders. And depending on how the function is defined and all that, You have to look at how each one is. And we'll see examples as we go. But for query selector, the generics for that is you can put angle brackets here. After that, before the parentheses, And you can tell it what type of data you expect this to return.
So now we look at element, you can see we still have, okay, it's going to give me an HTML element or an element. So it's basically just told query selector, this is the type it's going to be, or it could not exist. It's kind of the same as doing the as HTML or null. But this is the way I typically do my query selectors if I know like Obviously if you're selecting something with this class, and it could be a paragraph, an image, You might have to think about what data type that is.
So I could say, input element here. And now it's happening. So for query selector and query selector all, I highly suggest using the generic syntax.
We know there's not enough. There is another way to do that in TypeScript. Anytime You put... An exclamation point. At the end of your expression, That is, that symbol in TypeScript in that use case is called the not null assertion. Basically, you're telling it I know better than you, Ty Struick, and this will not be enough. So now we hover over Element and we can see Mel went away again. So if we got rid of this if statement, TypeScript's not gonna care, 'cause it's gonna say, "You told me it's not null.
So some best practices, right? You don't necessarily have to type everything. Use implicit typing when you can.
In Visual Studio Code, hover over things, see if it's typing it correctly. If it is, that's great.
So hover over it, you see an any, and that tells you, okay, I've got to go fix something. Um. Type inference. So Instead of any use unknown. So like this is a case where we're going to say, okay, we have a function that's going to take a value. We don't know what this value is. Let's say it could be a string. It could be a number. It could be an object. It could be all kinds of different things. You'd be tempted to say "Val" as "any." Well that gets a little dangerous because basically what NE does is turns off type checkers.
It doesn't work. So if you say value that's getting passed through this function is unknown, Then inside your function, you're forced to do narrowing and type checking before you can use it. So you could say something like if type of value is a string, Do this. If type of value is a number, do this. If type of value is an object, Do this. Like you can conditionally put logic in your function that's going to figure out what the type is before it does the logic.
Um... And then use interfaces for object shapes. We already talked about this earlier that I prefer that. I feel like it defines a very clear Let me use the word I use in the common here, contract.
So an interface is a, some of the language that's used is a contract for your data, right?
I'm telling you that if you have something that's of this type, this is how it will look. I just feel like interfaces are so much clearer for that.
We're going to take that application and move it into TypeScript. and see what the process would like to apply. How do you check for errors? All those different things. So, What we're going to do is we're going to end up using v. as our field tool. So the beat thatWell, We'll talk more about the probably later on, but from the most basic use case of it. I'm going to show you how you create a starter beat project here in just a moment.
The guide is pretty good. It's got all the documentation you need for the different frameworks. So these are the different projects that you can create in JavaScript or TypeScript versions. And it's got a scaffolding tool to create those projects for you. So it's It basically is all self-contained. It has some options, like different options for different tools that you can use within it. It will do your bundling for you, so not only does it give you a hot reloading dev server, it will also compile out static HTML and JavaScript, or you can deploy it to a website or something.
Uh. So Where we're going to startIs... So we've got this script conversion. I'll make this a folder here. So We're going to pick the start folder and I'll just bring it over here so we can have it here. Inside the start folder we have a demo OJS and an index HTML file. So what those look like Real quick we can look at The HTML file has some Simple CSS in it.
PHP in that folder as a server on port 8888. And then if I come over here and I do localhost, Index. Here's that same file actually hunting the JavaScript and inserting it into the page. So this is showing that the JavaScript version does run. Okay, before we start working on it, So that's our starting point. Uh. So what we're going to do is we're going to take that starting point We're going to create a VITE project that has a whole build environment and everything, and we're going to move that source code into the VEET project.
It will immediately be working. Because The feed's gonna run it. not going to care about the TypeScript errors. If we try to build it or we try to actually run the TypeScript check on it, then we'll start to see TypeScript errors. So let me create a program project here. So inside this folder here, TS Conversion folder. I'm going to go ahead and use the npm create-deet-at-latest.
It's also created us three Uh... NPM scripts, one called Dev, which runs which runs basically what the terminal is running now, the hot reloading dev server that we can just... Big changes, say, from F2. It gives us a build command which runs the TypeScript compiler and then runs the build. So what that's basically doing is it is running it through the TypeScript compiler to mostly just check for errors.
No skin. moved into the building also. Okay, so that's what we get set up. We get a tsconfig file that's got the default set to the way They want it set. You can see that they're targeting ES2022. Good morning. Most modern browsers will have no problem with that. The module system is using the ESNEXT, so it's manuscript modules.
It's saying ES 2022, so that's saying. Anything that's part of the ES2 and 22 language, you should know. Like TypeScript should know. It also is saying DOM. So anything that's part of the DOM API, Load the types for that. And it's also saying anything that's part of the DOM interval library.
And you see this "know a bit" is true. When that's set, what that does is if type TSC is run, it won't actually compile any files. All it's going to do is run the type check.
So we have everything kind of going. Okay. Right now main TS isn't being used so we can just ignore that for right now. And we have this orders.ts file. We see everything's running in our dev environment. All is good. Now, we saw when we tried to do the build. So I bring this up. And I try to run the npm run build and we see all the TypeScript errors in there. So we're going to get those. Insider terminal It's going to tell us what lines they're on, what errors they are, and everything.
on a total And then it returns an order ID, a total, and a formatted total. Okay, so the first thing we can do is we can say, okay, we need to haveOkay. some interfaces that describe what an order looks like, right? Because process order, It needs to take an order. Well, we have an order here. It's got an ID, it's got items, and it's got a tax rate.
So what does an order look like? What is the shape of an order? It's a property ID that's a string. It's a property items that is actually an array of items. We're going to have to create an item interface also. And then it's also a tax rate. property, which is a number. And then what does our item look like? An item is an object that has a name, which is a string, a price, which is a number, and a quantity, which is a number.
items, which is an array of item interfaces. So item objects, it's an array of those and a tax rate of a number. Okay, so we have that. Now we've just created two interfaces. We actually haven't typed anything yet. So if we still Start going in here and running this we're gonna get the same errors But now what we can do, we're going to ignore... It wanted to help us up here at first. And we're going to start down here at what process order looks like.
Format currency, knows it's taking a total in and it's coming out as a string. So all that is inferring pretty good. It's just this calculate total is not good. So if we come up here and look at company total, What do we have here? We're passing in an items, objects, and a tax rate. Okay. So... What is tax rate? Tax rate is Order tax rate, right? So it's this. We could use one of the utility types that we haven't talked about yet.
It says amount is n. So if we come back up here and look at format currency, the reason it's getting the return type correct is because it sees what the return line is. It's a string. It's a template string or a multi-line string, but number it doesn't know, or amount it doesn't know. So this is if it wants a number, We know it needs a number. So we'll put a number there. Now, When we hover over format currency, you can see that it is inferring that it returns a string.
Is it a string age? Is it a number age? We don't really know here. We're going to make an assumption that it's going to be an actual number. So we're going to go up and create another interface to describe this object that has those properties. Let's go up here. Interface user. First name string, last name string, age number, email string. Okay. So now we have This user object, we can come down here and say this user object is a user.
instead we'd be typing it as an object. So what we can do here is we can create a user info type that matches that object and type the return type of that function to this. So if we come up here and we do interface, User info. I think that's what it was, folding age and email. Woman names female. And now we can say that function returns a user info. And now it's tight. Same thing with this process order.
Process order is returning to us an order ID, a total, and a formatted total. We can call it whatever we want, but this is basically the result of our order or the So let's go make a border result type that is the order ID, the total, and the formatted type.
So there's a few ways we could fix this. I'm going to fix one of them. kind of the right way and the other one's the fast way, just so we can see all the options. So, like here? This is saying this is Mel. We could use a not null assertion here and say, oh, it's going to be there. And that one fixes that type of thing. So that's one way we could fix that. We can come down here In this one, And we could say We could do the same thing and do an assertion And we could do an assertion like we saw Earlier with as HTML And that's going to fix that one.
So now if we come back up here, let's fix this top one the more robust way that we probably should do it. So... What are we doing? We're getting this element here and we're setting inter-html on it. So let's do const. We'll call this-Calc, calculate total dev. And we will... Use thisHere. Put that there. So now calculate total depth as an HTML element or null. And now what we can do is let's Say If, so in this case, We're going to do it two ways.
It's still there because HTML element could be known, right? And we're trying to access a property on it. What we can do is we can say, If Nuts? Process order div. Throw new air. And now you see after this It knows that exists and it's not null because had it been null it would have thrown an error. So that's another way that we can Correct this null problem is if we actually want an explicit error found in our application, if we have a null value, throw an error.
This last page just says what are other ways to do tight narrowing. Bell statements, type offs, all that stuff. You kind of saw that earlier. Okay. Um. Assignments, we already skipped all that. I just linked to the TypeScript handbook. Um... We have quiz two due this coming weekend. I'm going to put a quiz up. about the topics from tonight.
This coming weekend, that'll be due. And then, like I said, Lab 2 is posted now.
정보
의존성 정의 방식