Advanced Patterns 11 exercises
solution

Type Helpers for React Components

Let's start by taking a closer look at the type helpers mentioned in the exercise setup.

Inside the type definitions, there's a message above ComponentProps:


/**
* NOTE: prefer ComponentPropsWithRef, if the ref is forwarded,
* or ComponentPropsWithoutRef when refs are not supported

Loading solution

Transcript

00:00 Okay, I asked you to take a look at a few different type helpers here, especially React or Component Props, Component Props with Ref, and Component Props without Ref. These are extremely complicated type helpers. But as you can see, they have a few different interesting things about them.

00:16 Notice that Component Props here, it actually says prefer Component Props with Ref or Component Props without Ref. So there's actually a little note on here saying that you should probably prefer these two when you're being descriptive. If you think about this, what situation are we in? Are we forwarding any refs? No, not currently, we'll get to that later.

00:37 But we're actually not forwarding any refs. So we should use Component Props without Ref probably. Let's just try adding that in first, Component Props without Ref. Okay, so we're no closer though. But what I want to investigate is actually looking at this and looking at its constraint.

00:56 Because if we look at Component Props without Ref, it actually takes an element type here. And an element type can represent, basically, if we look at it here, it's either one of these JSX intrinsic elements and look at it, it's actually like all of them there, or it's a component type. So Component Class, Function, Component.

01:15 We've had a look at this before, we sort of know what it does. And what I'd like to do is just what I found was worked really nicely for me is I can just stick in Element Type inside here. I'll just grab that from React. And now everything suddenly starts working.

01:32 So what we've got here then is we've got T as it's an element type, which is basically either button A or any of these, or you can pass in something custom, which is just glorious. And it just works out of the box. And because we're using Component Props without Ref, it just flows nicely.

01:51 So if we use Component Props, oddly enough, I couldn't get this working with this button or A or anything like this. We still get the same, in fact, the constraint breaks down as well, which is no fun. But everything sort of stops working when we use Component Props. And I think this is maybe a hint that when you have a complicated case like this,

02:11 you should be using Component Props without Ref or Component Props with Ref. So it's starting to come together, which is nice. I think the question is now, can we remove any of these casts inside here? So can I remove the as string? It turns out I can remove the as string, because T as now just represents any element type. Can I remove the props? Should I be so lucky?

02:31 I probably can't. Let's take a look. We've got expecting a type matching. No, it's extremely terrifying. Let's just slap the as any on there because we're now pushing up against TypeScript limits in terms of how fast its type checker can run.

02:46 So we probably want to, like, this is where you want to start using any relatively proactively to actually disable type checking in certain spots. Because actually, the less type checking we can get TypeScript to do on stuff that we know is OK, the faster it's going to run. Interesting area that we're now in.

03:06 This is some pretty scary stuff. But the fact that we've now got Component Props without Ref working for us, ElementType doing the constraint stuff for us, and everything else just playing along, it's starting to come together.