[Typescript] 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 {
rawConfig: {
featureFlags: {
homePage: any;
};
};
}
>(
...
Hovering over getHomePageFeatureFlags
in the tests will show the the entire object is being captured in the generic slot when using TConfig
as the type argument.
This means that we can index into TConfig
to find the type that the flag should be:
export const getHomePageFeatureFlags = < TConfig extends { rawConfig: { featureFlags: { homePage: any; }; }; } >( config: TConfig, override: ( flags: TConfig["rawConfig"]["featureFlags"]["homePage"] ) => TConfig["rawConfig"]["featureFlags"]["homePage"] ) => { return override(config.rawConfig.featureFlags.homePage); };
As you can see, this approach of capturing the generic on a higher level can be quite messy and captures a lot of unnecessary code.
Solution 2:
Using HomePageFlags
directly as the generic makes for a more elegant solution since it is the argument for the override
function.
We can now drill down to config.rawConfig.featureFlags.homePage
inside of the argument:
export const getHomePageFeatureFlags = <HomePageFlags>( config: { rawConfig: { featureFlags: { homePage: HomePageFlags; }; }; }, override: (flags: HomePageFlags) => HomePageFlags ) => { return override(config.rawConfig.featureFlags.homePage); };
With this solution, hovering over getHomePageFeatureFlags
in the test will only show us the stuff we care about inside of homePage
instead of the entire object.
// hovering over getHomePageFeatureFlags
const getHomePageFeatureFlags: <{ showBanner: boolean; showLogOut: boolean; }>...
Being able to access only the specific properties we want instead of drilling down twice makes the code much more readable.
A general rule of thumb for working with generics is to always represent them with a low-level type. As seen in the second solution, it's more efficient to drill down to find the specific type argument.