Search code examples
typescript

How to get the correct type of a nested object property?


I have a function which accepts a color as string like primary.500 and returns a hex color. All colors are stored in PALETTE object. So I just split string by dot and want to use the first array element as PALETTE object key and the second array element as value. But something is wrong in my code...I get an error on line colorValue = PALETTE[key][value]. How to fix that?

const PALETTE = {
  common: {
    white: "#fff",
    black: "#000",
  },
  primary: {
    500: "#222",
    700: "#333",
  },
  secondary: {
    500: "#444",
    700: "#555",
  },
} as const;

type Palette = typeof PALETTE;

type ColorVariant = {
  [K in keyof Palette]: `${K}.${Exclude<keyof Palette[K], symbol>}`;
}[keyof Palette];

type ColorVariantKey = {
  [K in keyof Palette]: Exclude<keyof Palette[K], symbol>;
}[keyof Palette];

type GetColor = ColorVariant | "inherit";

const getColor = (color: GetColor) => {
  let colorValue = "inherit";

  if (color !== "inherit") {
    const [key, value] = color.split(".") as [keyof Palette, ColorVariantKey];
    colorValue = PALETTE[key][value]; // here's the TypeScript error
  }

  return colorValue;
};

getColor("common.white");
getColor("primary.500");
getColor("secondary.700");

Here's Typescript playground.


Solution

  • The error occurs because Typescript cannot determine the exact type of color when you try to access PALETTE[key][value]. To fix this, you can use a type assertion as follow:

    const getColor = (color: GetColor) => {
      let colorValue = "inherit";
    
      if (color !== "inherit") {
        const [key, value] = color.split(".") as [keyof Palette, ColorVariantKey];
        colorValue = (PALETTE[key] as { [key: string]: string })[value];
      }
    
      return colorValue;
    };