Using Generics with Components 11 exercises
solution

Add a Generic Type Argument to a Props Interface

The first thing we need to do is convert our TableProps into a generic type.

To do this we will add a placeholder TRow type parameter to the TableProps interface and replace the rows: any[]:


interface TableProps<TRow> {
rows: TRow[];
renderRow: (row: any) => React.ReactNo

Loading solution

Transcript

00:00 Okay, let's start with the thing we know we need to do which is to turn table props into a generic type. So we can put a T here and I'm actually going to call this T row just to differentiate it from some of the other exercises we've done. Now T row here is going to take a row and it's also going to take this render row. So I'm going to put it in both slots here.

00:19 Now T row is basically if we were to instantiate this and say type example equals table props and let's just pass it ID string, then this means we're going to end up with the type that we probably specify. So type example 2 equals example, let's just say rows.

00:38 And here we're going to get, yeah, perfect, ID string inside an array. Lovely. So this is working. Table prop seems good. And we now need to pass it a type argument because it requires one type argument. So let's do that. Let's put that on here and let's pass it T row like that.

00:57 But T row hasn't been instantiated anywhere. How are we going to do that? Well, what we can do is just like every other function, we can put it at the start of this thing here.

01:08 Except you notice when I did that, when I opened up these brackets here, I get this weird thing where it thinks I want to put a react fragment there. So, okay, I need to just delete that indie bit there. And let me add T row inside here. Okay, something weird is going on. I'm losing my syntax highlighting here.

01:27 I'm getting this kind of strange thing. JSX element T row has no corresponding closing tag. It thinks that these angle brackets represent a JSX element, but they don't. They just represent a type parameter instantiation.

01:42 So the way you can do this, the way you can get around this, is by actually adding a comma on the end here. How strange is that? So just by adding a comma, it understands, okay, this isn't a JSX element. It's actually a type instantiation. The other way you can do it is by saying extends unknown, which is nice.

02:00 But I actually prefer the comma just because it's slightly terser. So when you're in TSX files, you need to do this because it doesn't understand that this is not a JSX component or a JSX element. So now we've done that. Is everything working? All the red seems to be gone from my little scroller on the side.

02:19 And yes, it is working. Wow. Hover over table here. We can see that it's now accepts T row as a type argument. And we've got rows data. Okay, that's being inferred properly. And you can see that when you hover over rows here, it's saying table props, and we can see what's being instantiated here.

02:38 So now row has row.name, and we can get proper autocomplete for what's available here. So render row, it's now properly grabbing this and does not exist, is erroring because it does not exist on the type that we're inferring. So there we go.

02:53 Just like we can have generic functions, we can have generic components. And this is really powerful because, you know, like components, they always return the same thing. They always return React nodes, right? Or in this case, JSX elements. And we'll get into the difference in that later in a section.

03:11 But they always return the same thing. And so components or generics are most useful in basically having different props that rely on each other. So here we have to infer this T row from the rows that are being passed in. You can think of it as kind of like a directional flow, right?

03:30 It understands, okay, T row is what's being passed in. And then the type of this function gets inferred from whatever rows is. So when you have kind of things like that, and this is a really great pattern. And this is really good for select components for, you know, when you have multiple options.

03:49 We're going to be looking at other things in this section too. So there we go. Our first generic component. Well done.