Home > OS >  How to make a special type using template string from object?
How to make a special type using template string from object?

Time:05-05

I have this object describing Legend for Chart component

export const MONTHLY_ANNUAL_LEGEND: Legend = [
  {
    title: 'Monthly',
    key: 'monthly',
    subItems: [
      {
        type: 'bar',
        key: 'progress'
      },
      {
        type: 'line',
        key: 'goal'
      },
    ],
  },
  {
    title: 'Annual',
    key: 'annual',
    subItems: [
      {
        type: 'line',
        key: 'progress'
      },
      {
        type: 'line',
        key: 'goal'
      },
    ],
  },
] as const;

And wanted to have a resulted type:

type LegendKeys = 'monthly_progress' | 'monthly_goal' | 'annual_progress' | 'annual_goal';

Which is a combination of MONTHLY_ANNUAL_LEGEND[number]['key'] and MONTHLY_ANNUAL_LEGEND[number]['subItems'][number]['key']

The first thing I've found is to make a builder-function which will return you a type, applicable for union type, but didn't found a solution to type subItems

function makeLegendItem<Key extends string>(item: LegendItem<Key>): LegendItem<Key> {
  return item;
}

CodePudding user response:

You can just use template literals:

type Legend = typeof MONTHLY_ANNUAL_LEGEND[number];

type Items =`${Legend["key"]}_${Legend["subItems"][number]["key"]}`;

CodePudding user response:

Using a recursive type which goes through the object would look like this:

type LegendKeys<T extends readonly any[]> = T extends readonly (infer I)[] 
  ? I extends Record<"key", string> & Record<"subItems", readonly any[]>
    ? `${I["key"]}_${LegendKeys<I["subItems"]>}` 
    : I extends {key: string} 
      ? I["key"] 
      : never
  : never

type Test = LegendKeys<typeof MONTHLY_ANNUAL_LEGEND>
// 'monthly_progress' | 'monthly_goal' | 'annual_progress' | 'annual_goal'

This has the benefit of working for any depth. So a subItem could also have its own subItems and the type would still work.

I had to specify readonly at multiple points since you used as const at the variable initialization.

Playground

  • Related