Search code examples
typescripttype-inferencestrong-typing

Typescript: Strong-typing (and autocomplete) for a value based on a sibling object's keys


Say I have an object that looks like this:

const configuration: Config = {
  options: {
    'Option 1': 'some value here',
    'Option 2': 'some other value here'
  },
  defaultOption: 'Option 1'
}

How can I write the type Config such that:

  • defaultOption can only be one of the keys in the .options object. ie. 'Option 1' or 'Option 2' in the case above.
  • .options can have any number of key-value pairs.
  • The user doesn't have to specify the .options keys upfront. So, the user shouldn't have to specify const configuration: Config<'Option 1' | 'Option 2'> = .... It's ok to use generics, but the user shouldn't have to specify them.

Solution

  • In order to do that and validate, you need to infer your config object from function argument:

    type Configuration<
      Options
      >
      = {
        options: Options,
        defaultOption: keyof Options
      }
    
    const config = <
      Options extends Record<string, string>,
      Config extends Configuration<Options>,
      Default extends keyof Config['options'],
      >(config: { options: Options, defaultOptions: Default }) => config
    
    const result = config({
      options: {
        'Option 1': 'some value here',
        'Option 2': 'some other value here'
      },
      defaultOptions: 'Option 1'
    }) // ok
    
    const result2 = config({
      options: {
        'Option 1': 'some value here',
        'Option 2': 'some other value here'
      },
      defaultOptions: 'invalid property'
    }) // error
    

    Playground