Advanced Props 12 exercises

Understanding and Implementing Dynamic Props Mapping in React

First things first, we need to discern a type for our buttonPropsMap.

Typing the buttonPropsMap

We'll define a type called Map which will be a Record with a string key and a value of ComponentProps<"button">.

type Map = Record<string, ComponentProps<"button">>;


Loading solution


00:00 Okay, let's see if we can solve this. This button props map here, we need to first of all just figure out a type that would even represent what this is trying to do here. It's kind of like a record or a map where the keys are component props button. So let's try and figure that out first.

00:18 Let's say type map for instance, equals a record and let's say string and now component props button here. So we've got this map and this looks good. I mean, this is a pretty horrible readout, but this is essentially what it's doing. It's an index signature on this object, which is a string.

00:36 And this huge React detail HTML props is just essentially an interface here that represents the button props. So we've got our map. Let's now take that map and use it on our button props map. So we've got map down here and this is really great. We're now getting auto-complete inside here.

00:55 The illegal properties have disappeared and it all seems well. Now inside our button here, we've got button props map props.variant and this all seems good too. But there's something wrong here. There's a single error. And this single error is the key to understanding this exercise

01:13 because now our variant has stopped working. This variant here, key of type of button props map is being inferred as a string, not as reset, submit or next. So this string here, the key inside of record is actually kind of key to understanding this. So we've got this record.

01:32 Now record here, we could actually manually type this. We could say reset or we could say submit or we could say button down the bottom. And okay, this now works here. Or does it work? No, because I put next or put button instead of next. This works.

01:53 And it means now that the variants down the bottom are all working. We've got next, reset and submit. Yay! Except this variant is now kind of lame because or rather this setup is really lame because we now have reset, submit and next, but they're not being inferred.

02:12 We now have this duplicated in two places. Wouldn't it be great if we could infer one from the other? Well, there seems to be no way around this because it's kind of circular, right? This is being typed as map and this is being sort of typed before we even get to map. Well, there is a way around it. Let's put string back in here and we're going to take this

02:32 and we're going to actually just delete this annotation. And just like in another exercise in this section, we're going to use satisfies here. And satisfies, what it's going to do is it's actually going to make sure that it satisfies that record string component props while not overriding the type. Yes!

02:50 So now we get reset, submit and next. And we've got these two types inside here, which means that we can then use them later to figure out this variant down there, which is just perfect. So we've still got the autocompletes here. And it means now that if we add a new one to this,

03:08 then we're still going to get autocomplete in here too and it's still going to be inferred down. So this means satisfies is a really, really nice way when you combine it with key of type of to actually still retain the responsibility principle for your types, a single source of truth, while still making sure that you can get autocomplete

03:27 on that source of truth.