0

I have a object with all of our design tokens like this:

const Tokens = {
  neutralColor: {
    dark: {
      '100': #123456,
      '200': #223456,
    },
    medium: {
      '100': #654321,
      '200': #876543,
    },
    light: {
      '100': #009988,
      '200': #334411,
    }
  },
  feedbackColor: {
    // similar like above
  },
  // other color family here
}

In my componente I need to limit the color props to only accept values in the tokens, like:

<Typography color={Tokens.neutralColor.dark["100"]}>label</Typography>

// or

<Typography color="#123456">label</Typography>
// since Tokens.neutralColor.dark["100"] = #123456

As I should, I should create a type like:

type Color = "#123456" | "#223456" | "#654321" | "and so on"

type TypographyProps = {
  color: Color
}

function Typography(props: TypographyProps) { ... }

Is there a way to create this Typescript type dynamically based on my token object?

Lai32290
  • 8,062
  • 19
  • 65
  • 99

2 Answers2

1

You can easily get type of any part of your object.

Notice that:

  • I changed your Tokens object to a constant
  • You can get a type of any object with typeof obj
  • you can get keys of any type T with keyof T
const Tokens = {
  neutralColor: {
    dark: {
      '100': '#123456',
      '200': '#223456',
    },
    medium: {
      '100': '#654321',
      '200': '#876543',
    },
    light: {
      '100': '#009988',
      '200': '#334411',
    }
  },
  feedbackColor: {
    // similar like above
  },
  // other color family here
} as const;



type LeafTypes<T> = T extends string
  ? T
  : {
      [Property in keyof T]: LeafTypes<T[Property]>;
    }[keyof T];

type Color = LeafTypes<typeof Tokens>

Playground link

Lesiak
  • 22,088
  • 2
  • 41
  • 65
1

Yes, it is possible :

  • declare your Tokens "as const", so that your color are interpeted as a literal type, not as string ;
  • get the deep value of your object.
const Tokens = {
  neutralColor: {
    dark: {
      '100': '#123456',
      '200': '#223456',
    },
    medium: {
      '100': '#654321',
      '200': '#876543',
    },
    light: {
      '100': '#009988',
      '200': '#334411',
    }
  }
} as const;

type DeepValueOf<T> = T extends string ? T : DeepValueOf<T[keyof T]>;
type AllowedColor = DeepValueOf<typeof Tokens>;

TS Playground

Blackhole
  • 20,129
  • 7
  • 70
  • 68
  • Thank you so much! It just works for me! I got a little bit about `typeof` and `keyof`, reading about it now, thank you so much again! – Lai32290 Sep 23 '22 at 18:44