How can I achieve typesafety for this converting case? I'm mapping over the palette
and convert any object with entries to key value pairs, like tailwindcss does for their color configuration. However the type of colors
don't contain the gray colors instead only the non converted entry keys as type.
const palette = {
white: 'white',
gray: {
100: '#eeeeee',
200: '#e0e0e0',
300: '#bbbbbb',
},
};
type ColorVariants = keyof typeof palette;
function convertToColors(color: ColorVariants) {
return Object.fromEntries(
Object.entries(palette[color]).map(([key, value]) => [`${color}${key}`, value]),
);
}
/**
result ->
{
"gray100": "#eeeeee",
"gray200": "#e0e0e0",
"gray300": "#bbbbbb",
}
*/
const grays = convertToColors("gray")
Types not correct here
// Resulting Type
// const colors: {
// white: string;
// }
//
// Expecting Type
// const colors: {
// white: string;
// gray100: string;
// gray200: string;
// gray300: string;
// }
const colors = {
white: palette.white,
...convertToColors("gray")
}
CodePudding user response:
You can now with template literal types.
Let's edit convertToColors
to this:
function convertToColors<Color extends ColorVariants>(color: Color): Variants<Color, typeof palette[Color]> {
return Object.fromEntries(
Object.entries(palette[color]).map(([key, value]) => [`${color}${key}`, value]),
) as never; // cast to return type; "ignore" error
}
It takes a color, and gives us the variants object for that color.
This is the proposed Variants
type:
type Variants<K extends string, T extends string | Record<string | number, string>> = T extends string ? T : {
[V in keyof T as V extends string | number ? `${K}${V}` : never]: T[V];
};
First it checks if the given color doesn't have any variants (it's just a string, not an object). Then it remaps all keys in the variants as the variant its intensity.
You can see that it works beautifully well here.
CodePudding user response:
you can use union in This case :
type ColorVariants = string | {[prop:number]:string};