Types Deep Dive 10 exercises

Understanding React's JSX Types

Solution 1: Differences Between Types

Let's start by looking at the type definition for React.ReactElement.


Inside of index.d.ts we see the definition for ReactElement:

// inside of index.d.ts
interface ReactElement<
P = any,
T extends string |

Loading solution


00:00 Okay, let's figure this out. So React.ReactElement, let's command click on ReactElement here. This looks like a very, very scary type, but what this represents is really just the thing that's underlying kind of like the, this is kind of what React.CreateElement spits out, basically is an object with a type.

00:18 It's going to be like div or span or something like that. It's going to be the props as well that it takes and the key here. So this kind of scary object here is a little bit interesting and it's also kind of a generic as well. You don't need to worry about this too much because of how it's defined in a couple of other spots. JSX.Elements here, let's take a look here.

00:37 JSX.Element extends React.ReactElement, okay. And you can see that it's actually not JSX.Element, it's just element. So where are we here? We seem to be inside index.d.js, inside the React types again, but where on earth are we?

00:54 Oh, we're in a global namespace called JSX. And in fact, you can see that there's a React.JSX here too. That's interesting, but we'll get to that in a minute. So we're inside JSX.Element. So JSX is a namespace, a global namespace, and we've got extends React.ReactElement.

01:14 This means actually that React.ReactElement and JSX.Element are assignable to each other. If we go like const, yeah, is a, let's say it's a slot that expects a JSX.Element, then we can actually pass it something which is a React.ReactElement. So let's say here, this is kind of like,

01:33 we're creating a React.ReactElement out of nothing. These two are assignable to each other and are virtually, I'm pretty sure, are completely the same. So React.ReactElement and JSX.Element, you can think of them as the same thing. So what is a React.ReactNode? Well, this is actually,

01:51 this contains React.Element in it. That's the first part of this massive union. And we've got string, number, ReactFragment, ReactPortal, Boolean, null, or undefined. In other words, these are all of the things that you can possibly render in a React component. And you've also got this do not use

02:09 or you'll be fired experimental React nodes. Lovely, perfect. Okay, well, we won't use those. So we can see then that React.ReactNode is the widest of the three here. These two are basically equal and this one is the widest of them. Now, what we can see here though,

02:27 is if we have some code and if we have some JSX here, and if we hover over this component, we can see that JSX.Element is the thing that's inferred from here. Depending on when you're viewing this, it might say React.JSX.Element. And let me just describe that too. What we'll see here is in this namespace React,

02:46 if we go all the way down here, we can see that there is JSX, React.JSX. Let's see where this is being grabbed here. What we'll see, yeah, you can see there that inside the React kind of namespace, there's another namespace here too, which is namespace JSX.

03:07 And JSX here basically has elements which extends the global JSX element. You can see there's a little bit of tricksy stuff going on, but currently React.JSX, what it does is it just mimics the stuff that's in JSX that it cares about. If you see React.JSX,

03:24 it basically means exactly the same thing as JSX. And in fact, they encourage people now to use a React.JSX to prevent kind of like pollution into the global namespace, which is good. So JSX.Element, React.JSX.Element, same thing. Now, we've got this return type of the components here. And you notice that whatever we put in here,

03:42 it's always going to be JSX.Element. So we can say, hello, maps or anything like that. We're not getting any special information back from this component. So it's always going to return JSX.Element. Now here, component two, React.ReactNode, what's going on here is that like, we can now return anything from this. If we were to actually manually annotate this

04:02 with JSX.Element, you can see that JSX.Element, that we actually can't return stuff like numbers here. We can't return null. We can't return undefined. So JSX.Element only represents that stuff in here,

04:18 only represents really JSX stuff components. So get rid of that. And this one then, this final question. So we know React.ReactNode can actually like, manage everything here. So everything that's possible to render, you can return from a React.ReactNode.

04:38 So null, undefined, all that stuff, all assignable to it. And why does this component not error, but this one does? Well, React.ReactElement is the same as JSX.Element. And so we can't like, let's look at the error here. Type string is not assignable to React.Element

04:55 because React.Element is that specific sort of object type. And also, you can return JSX inside or a JSX.Element in place of React.ReactElement. So all of that to say, is you probably don't need to worry about JSX.Element in your code.

05:14 You won't need to be actually manually writing this at all. It will pop up in errors though, time and time again, as will React.ReactElement. So if you're manually annotating stuff, you probably don't wanna use these at all because they're just too narrow. They don't represent all of the things that you can actually render in React.

05:32 And also, if you're actually trying to infer from them, they don't give you any useful information as we'll see in a bit. JSX.Element is the only thing that you can possibly get out of a construct like this. So you can't be any more narrow. You can't say, I want a specific type of JSX where it only has hello in there instead of hello, Matt.

05:52 And this becomes an issue later as we'll see. So there we go. Those are these three elements. React.ReactElement is the same as JSX.Element which fits inside the wider type and more useful type of React.ReactNode.