#How can I derive a type from a complex object where keys may be present/absent?

8 messages · Page 1 of 1 (latest)

sullen brook
#

I’m trying to define a type for a Theme definition object, which basically follows this structure:

const themes = {
  default: {
    dark: THEME_VALUES_DARK,
    light: THEME_VALUES_LIGHT,
  },
  other_dark_theme_name: {
    dark: OTHER_THEME_VALUES_DARK,
  },
  yet_another_light_theme_name: {
    light: YET_ANOTHER_THEME_VALUES_LIGHT,
  },
};

As you can see, not every theme supports both light and dark modes. There’s two things I’d ideally like to do here:

  1. Create an object defining the structure of which themes support which colour modes (to make it easy to iterate over all the available themes and colour modes). I’m thinking something like:
const THEME_SUPPORTED_MODES = {
  default: ['light', 'dark'],
  other_dark_theme_name: ['dark'],
  yet_another_light_theme_name: ['light'],
};
  1. A type which derives the types of values available in THEME_SUPPORTED_MODES or (if it’s more practical) to apply that type directly to the themes object above. I want to ensure that accessing members of themes is always done in a typesafe way, so that e.g. const values = themes.other_dark_theme_name.dark is typesafe, but const values = themes.other_dark_theme_name.light is not.

Can I achieve this with TypeScript, and if so how?

sullen brook
#

I’m trying to break this problem down into smaller parts so I can understand it more thoroughly, since this involves some types I don’t use often. One thing I was wondering about was how to derive a string union type from the specific values of dark or light associated with a given theme, based on this stackoverflow post.

I was thinking for example I could derive a string union like this:

const THEME_SUPPORTED_MODES: Record<ThemeName, ThemeColorMode[]> = {
  default: ['light', 'dark'],
  other_dark_theme_name: ['dark'],
  yet_another_light_theme_name: ['light'],
};


type OtherThemeModes = typeof THEME_SUPPORTED_MODES.other_dark_theme_name[number];

I’m expecting this to evaluate to :

type OtherThemeModes = 'dark';

but actually I get:

type OtherThemeModes = 'dark' | 'light'

(I realise that the SO post uses as const on the array of possible values, whereas I’m using a member of another object literal which does mean there’s already some differences here… probably why it doesn’t work)

vestal mason
#

maybe you want satisfies rather than a type annotation?

#

like this:

undone estuaryBOT
#
mkantor#0

Preview:ts ... const THEME_SUPPORTED_MODES = { default: ['light', 'dark'], other_dark_theme_name: ['dark'], yet_another_light_theme_name: ['light'], } satisfies Record<ThemeName, ThemeColorMode[]>; ...

sullen brook