Advanced Patterns 11 exercises
solution

Typing the Children Prop for Render Props

The first step to solving this problem is to type the children prop in the Modal component.

Here's what we started with:

const Modal = ({ children }: any) => {
  ...

We'll update it by declaring an inline object type for the children prop, which we will set as unknown f

Loading solution

Transcript

00:00 Okay. So the way to solve this is we're just going to declare inside here in an inline object type, we're going to type this children property. And this children property, let's just currently stick it as unknown. But let's look at what it looks like inside the component.

00:15 Inside the component, children is a function which takes in a bunch of properties and returns... Well, what is it supposed to return? Let's just type this out first. We actually know that these props are going to be modal props or modal child props, which are just up here. And then what is it supposed to return?

00:33 Well, let's just say it returns, I don't know, undefined for now. Well, down here, we know that the thing it's supposed to return is some JSX. And we know the proper type for that is going to be react.reactNode because we want it to be flexible enough that it can pass a number, a Boolean string or null or undefined or anything.

00:52 So this seems to be working. So this is kind of like a slightly mind-blowing idea when you first look at it, that you can actually type children something other than react.reactNode. It's a function that you can call. If we try to pass it something that doesn't work here, let's say we just pass it a div,

01:10 then it's going to yell at us because this isn't a kind of assignable to a function that returns react.reactNode. And in fact, there's an even simpler way to type this. What do we know that looks like this signature? Well, it's a react.fc. And react.fc has modal child props attached to it.

01:29 So this is, I think, the most succinct definition for this, which is you're basically just passing in the raw definition of a function component into them. And that's kind of interesting. There's another way that you can potentially sort of design this API as well,

01:44 which is instead of using a children prop here, you can use like a render prop. And we'll just rename all of these render. And now, of course, this doesn't work. We actually need to grab this and stick this in a render prop, which is where it actually gets its name here.

02:02 So now what we have, you can actually pass in multiple of these if you want to be really, really, like use a really dynamic structure for where you want to render all of these elements. So here what we're doing is we can actually, let's just rename this like renderButtons, for instance. And then inside the modal, we could potentially just renderModal.

02:20 So this gives you a really nice API for basically wrapping this piece of state and wrapping the createPortal functionality, and then everything else you can kind of just like provide to the consumer of your components. And this isn't something that you can necessarily do with just pure hooks alone. Very, very cool.