Check out a free preview of the full Intermediate React, v4 course:
The "Typing a Custom Hook" Lesson is part of the full, Intermediate React, v4 course featured in this preview video. Here's what you'd learn in this lesson:

Brian refactors the useBreedList custom hook to use TypeScript. An enumerated Status type is added to the component to enforce the specific string values of the status state. A BreedListAPIResponse type is added to the APIResponseTypes component. A question about using the void keyword when handling async functions is also covered in this segment.

Get Unlimited Access Now

Transcript from the "Typing a Custom Hook" Lesson

[00:00:00]
>> So let's pop over to pet.jsx. Well, JS, and then we're going to rename it to pet.tsx. Okay, so let's go ahead and grab function component import, function component from react, and we're gonna make this pet a, function component and it's got a bunch of props here. Obviously this is not a, class component, so let's go ahead and give it some, IProps or props or whatever you wanna call this little thing here.

[00:00:42] And we're gonna just make an interface, IProps, and it's gonna take a name which is a string. It's gonna take an animal which is a string. Take a breed, which is a string, images, Which is a string array, and location, which is a string and ID which has a number, okay?

[00:01:16] Now I imagine at least someone out there is thinking is like, why don't we just make this pet? Well, I'm gonna give you two reasons for that. One, location is actually different, right? So if you remember in pet and I'll bring that up here so you can see our API response types.

[00:01:34] This gives you city and state and you might remember from writing in Complete Intro to React, we actually put those things together as one thing, which is a location, so these actually don't match each other. The other thing is just kind of a personal preference. I try not to make these function, I always do an IProps thing and then I'm specific at what I expected in a component one, this kind of documentation for this component.

[00:01:56] And two things change over time. They may not be a pet, they might be a pet and a thing, in which case you get into union typing and things like that and you're just out in weeds, and at that point it's like, just be explicit. This thing expects this and then it makes it easy to maintain and read going forward.

[00:02:16] Don't get clever with types, please don't get clever with types, just be explicit, Okay, that's it for this I think. I think everything else is just fine. So that's all good. So let's keep going. We're gonna go do use BreedList. We're going to rename this to use pre this ts, there's no JSX in here so we don't need it to run it through there.

[00:02:50] Okay so let's add something to our, API response types up here. So go back to that for just a second. And we're just gonna export a new type in here, which is a BreedList API response. So export interface. BreedList API response. I like to keep these API response things in separate in their own files.

[00:03:24] If I ever had to call this BreedList somewhere else, it wouldn't be stuck in this weird location of being, hey, you have to import this custom hook to get the correct type. That seems weird to me, it makes more sense of like, hey, I have an API response.

[00:03:36] I expect that to find that in the API response TypeScript file This is preference, I leave it up to you of what you think is a better way of doing that. This just makes sense to my lizard brain that I have. So an animal, an animal, and breeds is just an array of strings.

[00:03:59] Okay, pretty simple there. Obvious are at least not a lot to it. We're gonna go back to use BreedList now and we're going to import that type that we just made. So we're going to import animal and BreedList API response. From ./APIResponseTypes, okay? So local cache, this one's kind of fun thing to type.

[00:04:29] Because what is local cache gonna be? Local cache is going to be a list of arbitrary keys that then represent objects of responses are strings rather. So how do you type that in TypeScript? Well, you're gonna have an object, right, which is what it is, oops, and then it's going to have arbitrary indexes, which are strings, right?

[00:04:57] Which is what this square brackets are, okay? And then those are going to represent strings arrays. So this is just saying like, I don't know what the strings are actually gonna be in here, but it's just gonna be arbitrary, right? So these are gonna be indexes or whatever you choose to call them.

[00:05:17] And then those are gonna be strings themselves. And now we have local cache, which as you can see here, it has arbitrary strings as its keys and then those keys are going to represent string arrays. Okay, and then I'm gonna have a type status in here. And I'm gonna keep this type in here because this is actually very specific to this custom hook that we wrote.

[00:05:43] And it's gonna be a enumerated type it's either going to be unloaded or loading or loaded which is what we returned down here, okay? So, function use breed this animal as you may guess is a animal. Okay, BreedList and setBreedList, this is an array, but we need to tell it what type of array it is.

[00:06:24] So this array is an array of string. So now it knows that this, because we give it a default thing here in useState, it's smart enough knows okay, this is going to be a string array that I'm going to get back. And this is a thing that you can only call with a string array.

[00:06:43] So react has really good typings that way. Same thing with status and set status. Right now and things like this is a string and we have to let it know specifically that this is a a status. So now it knows that you can only call this with unloaded loading or loaded and if I call with something else it's gonna be upset.

[00:07:07] Okay, we're gonna have to cast our API response here. So this you're gonna have to wrap in this, wait, This is going to come back, actually it's the JSON, sorry, it's this one that you cast. So whatever this comes back as, we want to cast that as a bBeedList API response.

[00:07:33] So now we know this JSON object has all the things that we expect out of a BreedList API object. Okay. Let's see what did we miss here, requestBreedList. This was kind of a fun one. So, request free list is a function it's an a sync function in what do all asynchrony functions return, promises, So basically any with an a sync function, no matter what, if you call it the thing that you get back from it as a promise, and then you can await the promise to get whatever you get back from it.

[00:08:22] You can see here that we actually don't return anything out here. So if you awaited this you would get undefined, right? But still, this is still giving you back a promise. This is telling me here and I think this is actually from es lint. It is TypeScript, floating promises.

[00:08:42] It's basically saying, you need to explicitly tell me that you're ignoring the promise here. So the way that you do that is you just say void, and that's explicitly saying I do not care what comes back from this promise. Cuz we're just calling this and we're using a sync to make it so that we can use a sync a weight, right?

[00:09:04] So we actually don't care about the promise coming back hence you have to say I'm calling something here, but you can ignore it and move on. So this will actually make sure that it returns everything. Like if you do this x will now be equal to, Undefined right void.

[00:09:26] This keyword void basically means I'm going to give you something after it. It's a unary operator, if you want to get into the technical details. Whatever comes after this, make it undefined, cuz I don't care what it is. Not something we use a terrible much in JavaScript, because why would you want to make something undefined.

[00:09:44] This is the one case that you probably wanna do that. Again, this is an ESLint rule that's making us do this TypeScript in general wouldn't care. It's just ESLint that cares. I probably would just go and ignore that rule if it was me on my own project, cuz this doesn't really tell me very much.

[00:10:02] This and that tell me the exact same thing, but someone somewhere felt it was important to enforce that on us. Okay, any questions so far?
>> Just real quick, just double check, void is from just JavaScript it's not TypeScript [INAUDIBLE].
>> Correct.
>> That's what I thought.
>> Void is a JavaScript keyword.

[00:10:28] We just never use it. The only reason that you would ever use void is if you wanted to explicitly communicate your code I don't care about this. But usually that's fairly implicit. In other words, I have never used void outside of this particular use case.