Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I correctly type this object converting?

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")
}

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading