TypeScript: From First Steps to Professional

Add Types to Event Methods

Anjana Vakil
Software Engineer & Educator
TypeScript: From First Steps to Professional

Lesson Description

The "Add Types to Event Methods" Lesson is part of the full, TypeScript: From First Steps to Professional course featured in this preview video. Here's what you'd learn in this lesson:

Anjana demonstrates how to specify types for function parameters and return values to help TypeScript understand the code better. Anjana also explains the use of async functions, promises, and handling errors, showcasing how TypeScript infers types based on the provided information.

Preview
Close

Transcript from the "Add Types to Event Methods" Lesson

[00:00:00]
>> Anjana Vakil: Alright, we're down in error, huzzah What else we got in this file Hm Mhm Can somebody help me help TypeScript here It hates it when we give it implicit anys if we have no implicit any turned on in our compiler options So, let's fix it How did folks type this function signature here We have a suggestion for title colon string Events colon and event array Haha So yes, we're seeing that we're going to call an events map

[00:00:43]
And this is sort of like for a group of events, we're going to generate a little like collection of them, and then we're going to create an event card for each one And similarly to what we saw before, this E in our little anonymous arrow function here that we're passing into map is implicitly any But so if we tell TypeScript, hey, this event parameter that's coming in, it's going to be an array of events which we tell it by the type and then the square brackets after it

[00:01:22]
Notice that not only did the event squiggle go away, but also the squiggle on this E right here, because now TypeScript can infer It knows that events is going to be an array of events And it knows what map does in JavaScript We briefly saw this earlier, when we hover over a map, we see that it's an array of event in brackets, and that's those generic types, those type parameters that we saw under the hood

[00:02:01]
That's what's happening with this special syntax that we have for making arrays out of types And so it knows that the map function is going to, the map method is going to get an individual item out of that array So it is inferring the type of E to be an event because it knows the type of events and it knows the signature and the structure of the map method Now this is we don't need to understand every tiny little character here, but this is the kind of inference that makes our lives way easier as TypeScript developers

[00:02:42]
Imagine if we had to put a colon type annotation next to every single variable we use everywhere and anonymous functions and la la So the TypeScript compiler infers as much as possible for us Making us do the least amount of typing possible for it to know all of the information it needs to follow the instructions we gave it in tsconfig.json, and hopefully we're now down another few errors, yay

[00:03:21]
Oh, we got one more squiggle in here We're going to need to think a little bit about this one We're calling similarly to our map that we called on the events earlier, which didn't have a type and therefore squiggle because E here implicitly has an any type We get the sense that TypeScript has no idea what is coming back from this load events data, await load events data

[00:03:56]
So if we go to definition here, jumping up further in the file And we hover, we see that TypeScript knows that this is a promise But it has no idea what that promise is going to return And so inside those angle brackets, the type that it actually infers for the promised thing is any And it therefore is going to understand down here that since this is any, filters, any

[00:04:42]
And the function inside that we passed into the filter is also any, like there's no information here We got anys all the way down So did anybody figure out a way to tell TypeScript What kind of thing Here we go What kind of thing we expect this promise to give back to us, like this function, which is asynchronous, and that's where that async is what's allowing TypeScript to infer that this is going to return a promise to something, it just doesn't know what, but it sees the async

[00:05:19]
Thanks, TypeScript So is there a way that we can explicitly tell TypeScript the return type of a function Promise with the angle with the but I don't remember where exactly it goes OK, cool So we do want to tell it it's going to be a promise to something within angles, totally, bingo And the question is where do we put that colon promise, whatever If we are talking about parameters to a function, they would go in here

[00:05:51]
Whatever But then of course I get a oh you're not using this It's declared, but it's never read That's another setting that you can kind of strictify or not strictify whether TypeScript is going to be like, you have unused variables, clean up after yourself, or maybe you forgot to use the variable because you accidentally deleted more lines of code in your last commit than you intended to, for example

[00:06:20]
OK, so when we're annotating the type of a function, we annotate the types of the parameters inside of the parens And the return type, we can annotate right after those parens So here, like if it was going to be a number Uh TypeScript would find that strange because the return type of an async function or method must be a promise And so it's like, did you mean promise number

[00:07:00]
And now it's like, well, hang on, you're not actually returning a number And here we again we have that function lacks ending return and return type does not include undefined Oh boy But in any case, we're not trying to return promises to numbers here What do you think that this fetch API URL events is going to give us back It's an event So remember earlier, very briefly, we started running the API server and then we basically completely neglected it

[00:07:40]
But if we go back, what happens when we at our localhost 3000, we have our API server running, and there is an endpoint slash API slash events, and if we hit that We get some JSON And this is just Firefox making the JSON pretty for us, but if we want to look at it less pretty, we can look at the raw data But either way, we notice there's a bunch of numbers here and a bunch of objects

[00:08:13]
So what kind of thing does this look like And hint, if you look at the first character of the raw data It's an array of events It's an array of event objects So, we need to tell TypeScript that what it can expect back from this load events data or load events or what did I name it Load events data What it's expecting back is ultimately going to be an array of events

[00:08:49]
However, it's asynchronous So it's going to be a promise of an array of events Not numbers And so, let me take out the number and then it's saying, hey, hey, hey, whoa, whoa You see those angle brackets Yeah, they're not just for funsies They mean that the generic type, we talked briefly about these are types that take in parameters Um, here its parameter is called T, which is very common, and it's saying, hey, you didn't actually pass in an argument to this type parameter that I'm expecting

[00:09:25]
So what are you going to promise me here, huh And what are we going to promise it An event event array OK Now, we're back to our hang on now Lack ending return statement So now we have a code change we need to make, not just a type annotation we need to make So is there a case where this function is going to implicitly return undefined If there's no events If maybe if there's no events during an error, or if there's an error, if so with this try catch

[00:10:13]
What we are doing is saying, OK, we're going to try to hit this API endpoint, but all kinds of stuff could go wrong there, right The API could be down I might have forgot to start the dev server Um, the endpoint might be returning nothing, it might be the wrong endpoint, it might be something else going wrong I might have a 404 or a 402 payment required or something like that

[00:10:42]
So there's all kinds of stuff that can go wrong with a fetch And that's why you often see fetches and try catch blocks So what we're doing in this catch block is we're essentially kind of silently failing out of our intended functionality, which is getting this response and returning the JSON Instead, what we're doing is we're just erroring, we're writing a red line to the console with whatever we got back from this, um

[00:11:18]
From this catch here, whatever the thing was that went wrong But because we're just error logging it to the console We're not actually explicitly returning anything here, which means we are returning undefined, it implicitly, yes Is that what we want in the case where we can't load the events for some reason Or we could return an empty array perhaps Perhaps we could do that

[00:11:54]
Something like return an empty array, because at least the code will know what to do with an array But it might not know what to do with undefined So if we return empty array Now, TypeScript Is chill What amazing progress Now, it knows that the return value of this asynchronous function is always going to be a promise to an array of event objects That array might be empty

[00:12:44]
But it'll still have the same type And so now we are squiggle free since 3 seconds ago OK Let us run our tsc That I didn't save, let's save and then run our tsc and we are down to 2 files with problems Let's take a moment to enjoy our victory OK Can you explain more about what the E is in the catch Like where's that being defined Great question And so this is something that we're um

[00:13:16]
We haven't talked a lot about and we're not going to cause it's a little bit more Requires a little bit more depth than we're getting into in this course, but the unknown type shows up here And this is a type that's not the same as any, where any says, hey, I really couldn't care less what type this is Unknown is like, no, no, I care what type this is, I just don't know what it is yet

[00:13:46]
And this is kind of a, you can look this up later, but like um What type the error that is caught in the catch side of a try catch should have is kind of a like question of philosophy, I guess, but um, but so here I named it terribly What you might often see it named as like an error, but um, it's a good point, and yes, and this is why you shouldn't name variable single letters because it can be confusing for people who are reading your code when you have E for event and E for error all over the place

[00:14:27]
Apologies and also welcome to web dev We're the worst Now That's really helpful I have one other question on the return Is that a is that a typed object of some sort, or how does this right here Yeah, I'm trying to think it's like, is it technically part of the or is it just part of the language so it doesn't matter Great question So How does TypeScript know that when we return this array, well, so there's kind of two questions here

[00:14:58]
How does TypeScript know that this is going to be a promise to an array And how does TypeScript know what type of array the empty array is Like, does it make sense for an empty array to have a type And that's where TypeScript is making a bunch of inferences here So, first question is, how does TypeScript know that this function is always going to return a promise

[00:15:30]
And that is not something that um Is based on how I annotated the function, it is just this keyword async TypeScript knows because it knows JavaScript, and it knows about async JavaScript and promises and all of that good stuff which If you're newer to the JavaScript or the web world, it might be a lot to wrap your head around Um, so it's something you can definitely go read up on

[00:15:59]
MDN is your friend, as I say a lot in my internal JavaScript, JavaScript first steps course, um So what TypeScript says or thinks here is, OK, I see an async, that means whatever comes back from this function, if it's undefined, if it's gobbledygook, it's going to be promise of that OK, so then the question is, how does TypeScript know that it's going to be always a promise to an event array

[00:16:34]
And here's where, well, we told it And then it sees a return of an empty array And because we told it that the return type of this function is always going to be an event array It knows that this empty array, it's not just any kind of nothingness that it contains, it's an eventy nothingness that it contains, and that sounds a bit weird when you're thinking like it's an empty array, like aren't empty arrays kind of all equivalent

[00:17:09]
But the thing is, if we're dealing with them later needing to handle this array And we don't know whether, um, it'll always be the same type of thing, what have you, and sometimes we get an empty array if we didn't have this information, this inference that this function always returns an event array and there's just an edge case where that array might be empty, then TypeScript wouldn't be able to infer that, for example, when we're doing a map operation over our events

[00:17:41]
Each thing passed into that map, which might be nothing, each thing if it is passed in, is going to be an event So there's kind of two different layers of inference and one of them is more implicit about the promise thing and one of them is more explicit because I told it what an event is, what my event is, our kind of event, not the browser's kind of event, and the angle brackets told it it's going to be array and so that's where it's putting all of that information together and this is just a tiny little tip of the iceberg of all of the stuff, all of the info that tsc just like gobbles up from your whole code base and all of the code bases of your dependencies and all of the other types you point it to

[00:18:23]
And it's just like, let me know all of the information that I may see into your mind And it's reading our minds, kind of Last follow on with this break if we took the array off of the promise event array Like would that break the underlying assumption that it will return Only one way to find out That's my guess And so here, yeah, you said that this was always going to return a promise to an event

[00:18:54]
And yet you gave me this thing, and here we're seeing another fun little type that you'll run into Never It's going to say, this is an array that is never going to contain anything because you put nothing there and there's no like dynamic work that we're doing to figure out if there maybe should be stuff in the array and populated or anything like that We're just returning a blank empty array

[00:19:23]
And forever shall it stay empty That's what we're seeing here What's happening now is that essentially, it doesn't care that the fetch, like it doesn't know anything about our API It doesn't know anything about what kind of stuff is going to come back from this endpoint yet But it does know that we promised that this would be a promise to be a to be an object with the type that we declared in our interface earlier and so that is not satisfied by an empty array that's never going to have anything

[00:20:05]
Um, but for now, we're going to take solace in the fact that this turned green up here And we've, we went down from 3 files with problems to 2 files with problems, and we are going to go look up types like unknown and never and all these fun not really things types on our own time later.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now