Home > other >  How to infer object key type based on another key in Typescript
How to infer object key type based on another key in Typescript

Time:08-09

I have a type with key-value pairs, where keys are React component names and values are the values they take as props. What I am trying to do is to type an array of types containing the type field, which is also the exact name of a component, and a getter and setter functions that use component values types.


type ElementValues = {
    text: string,
    checkbox: boolean
}

type ElementType = keyof ElementValues

type Value<Type extends ElementType> = ElementValues[Type]

type Test = {
    [Type in ElementType]: {
    type: Type
    getter: () => Value<Type>
    setter: (value: Value<Type>) => any
}}[ElementType]

const testList: Array<Test> = [{
    type: 'checkbox',
    getter: () => 'test,
    setter: (value) => ({ })
}]

What I can get is the array with elements that do not care about the given component name and take all possible component value types as setter and getter params/return types.

In the above example, getter should require boolean, as for checkbox value, and setter should have a value type of boolean, not boolean | string.

CodePudding user response:

The following would do the trick. Just use discriminated unions. This way the array elements are going to be discriminated by the type field (text or checkbox).

type ElementValues = {
  text: string,
  checkbox: boolean
}

type ElementType = keyof ElementValues

type Value<Type extends ElementType> = ElementValues[Type]

type Test<Type extends ElementType> = {
  type: Type
  getter: () => Value<Type>
  setter: (value: Value<Type>) => any
}

// Here - Discriminated Unions
type Elements =
  | Test<'checkbox'>
  | Test<'text'>

const testList: Array<Elements> = [
  {
    type: 'text',
    getter: () => 'test1',
    setter: (value) => ({ })
  },
  {
    type: 'checkbox',
    getter: () => true,
    setter: (value) => ({ })
  }
]

CodePudding user response:

It seems that adding helper type Elements solved the problem. Based on @lepsch answer:

type ElementValues = {
  text: string,
  checkbox: boolean
}

type ElementType = keyof ElementValues

type Value<Type extends ElementType> = ElementValues[Type]

type Test<Type extends ElementType> = {
  type: Type
  getter: () => Value<Type>
  setter: (value: Value<Type>) => any
}

type Elements = {
    [Type in ElementType]: Test<Type>
}[ElementType]

const testList: Array<Elements> = [
  {
    type: 'text',
    getter: () => 'test',
    setter: (value) => ({ })
  },
  {
    type: 'checkbox',
    getter: () => true,
    setter: (value) => ({ })
  }
]

  • Related