The Art of Type Arguments 9 exercises
solution

Represent Generics at the Lowest Level

There are two solutions to this challenge, both with different ways of representing the generic.

Solution 1

The first option is using TConfig which extends rawConfig and includes featureFlags, homePage, and any:

export const getHomePageFeatureFlags = <
  TConfig extends
Loading solution

Transcript

0:00 There are two solutions here, and this is all about how you represent the generic that's in the type parameter here.

0:09 The first option is we have TConfig extends { rawConfig: { featureFlags: { home page: any; } } } and it then depends on how you want to handle the override function.

0:20 This means that when you pass in TConfig here, if we go to one of the call sites, we can see that the thing that's being captured in the generic slot is the entire object that's being passed in, this example config.

0:32 What that means is that TConfig, then, we can index into it to find the type that the flag should be. We should be able to rawConfig in there, featureFlags, and then home page there.

0:44 This is a little bit messy, actually. It's got quite a lot of code. We're representing the generic on quite a high level, so quite a lot is being captured inside this argument here or this type parameter.

0:58 The second solution, I think, is a little bit more elegant, which is we have our home pageFlags here. This is exactly the thing that we want to capture here because it's the argument inside the override function.

1:10 We have our override function, which is home pageFlags. Now, inside the argument of the function itself, we do the drilling there.

1:18 Instead of drilling twice in this one, where we represented the entire thing at the top level and then drilled down twice to get the actual config, what we do is we represent it at the low level in the generic slot and then just do the drilling inside this argument here.

1:37 This means that at the call site it's then only accessing these two things, the things it cares about, which is the things inside home page, showBanner 1, showLogOut false. It means that less gets captured in here, which is pretty nice, actually. It means this is a little bit more readable when you hover over it.

1:55 We can add something else to here and say showMatt: "always". Then inside there what we'll get is showMatt: string. Very, very cool.

2:06 This in general is quite a nice rule of thumb for when you're working with generics, is you should always try to make this generic type argument represent a low-level thing. This is going to come back a few times to us.

2:22 If you have an option between choosing a high-level representation representing the whole thing, lots of stuff you maybe don't need, then in general it's best to drill down and find exactly what you want the type argument to represent because, in this previous example, we would have to do a lot of drilling ourselves.

2:39 There is a slight way that you can change this if you want to, which is to say Thome pageFlags equals this, and extract it out into a default generic like this.

2:53 We will look at this in more detail a little bit later, but this is a little bit of a hack around the issue, and I feel like the second method is more elegant.