How to build a Typescript type from an array of strings?

Viewed 77

So far I have this.

export const PacerThemes = ['Default', 'Dark Muted', 'Neon'] as const;
export type PacerTheme = typeof PacerThemes[number];

type ThemeProperties = {
  exhaleHoldBorderColor: string;
  exhaleHoldColor: string;
  inhaleHoldBorderColor: string;
  inhaleHoldColor: string;
};

type Themes = {
  Default: ThemeProperties;
  'Dark Muted': ThemeProperties;
  Neon: ThemeProperties;
};

Is there a way to generate the Themes type from the PacerThemes array?

2 Answers

You could use a Mapped type, as suggested in the comments.

    type ThemeNames = "Default" | "Dark Muted" | "Neon";

    type ThemeProperties = {
      exhaleHoldBorderColor: string;
      exhaleHoldColor: string;
      inhaleHoldBorderColor: string;
      inhaleHoldColor: string;
    };

    type Themes = {
      [T in ThemeNames]: ThemeProperties;
    };

Or you could use a Record utility type

    type ThemeNames = "Default" | "Dark Muted" | "Neon";

    type ThemeProperties = {
      exhaleHoldBorderColor: string;
      exhaleHoldColor: string;
      inhaleHoldBorderColor: string;
      inhaleHoldColor: string;
    }

    type Themes = Record<ThemeNames, ThemeProperties>

TS Playground

Here's a solution (Playground link):

const PacerThemes = ['Default', 'Dark Muted', 'Neon'] as const


type ThemePropertiesVersion = {
  [k in (typeof PacerThemes)[keyof typeof PacerThemes & number]]: "YourType"
}

If you wand to make this more generic by introducing some reusable helper types, you might encounter the problem that readonly any[] does not extend any[].

For example, this would not work, since typeof PacerThemes is readonly:

type Items<A extends any[]> = A[keyof A & number]

To handle this you could to something like this (Playground link):

const PacerThemes = ['Default', 'Dark Muted', 'Neon'] as const


// Version 1 -- allow only readonly arrays

type ReadonlyItems<P extends readonly any[]> = P[keyof P & number]

type TestVersion1 = NonRestrictiveItems<typeof PacerThemes>

type ThemePropertiesVersion1 = {
  [k in ReadonlyItems<typeof PacerThemes>]: "YourType"
}


// Version 2 -- allow both

type NonRestrictiveItems<P extends (readonly any[]) | any[]> = P[keyof P & number]

type TestVersion2 = NonRestrictiveItems<typeof PacerThemes>

type ThemePropertiesVersion2 = {
  [k in NonRestrictiveItems<typeof PacerThemes>]: "YourType"
}
Related