Typescript , How to infer type from another property value?

Viewed 1100

For example, I have an interface with properties: key and value, I want to infer value type by the key.

interface Obj { a: number; b: string }

interface Param<K extends keyof Obj> {
  key: K
  value: Obj[K] // I want to infer this type
}

const p: Param<keyof Obj> = {
  key: 'a',
  value: '', // typescript can't infer this type, expect number
}

How can I do that ?

3 Answers

Obj[K] means a value that can be gotten by indexing Obj by any of the values in K, not just the one key is.

So, to use this structure, you need to specify which key is used more closely:

interface Obj { a: number; b: string }

interface Param<K extends keyof Obj> {
  key: K
  value: Obj[K]
}

const p: Param<'a'> = { // changed line
  key: 'a',
  value: '', // error
}

There's no way to infer the generic parameter, sadly.


If you already know what's in Obj, there may be a better way to do this.

interface AParam {
    key: 'a'
    value: number
}

interface BParam {
    key: 'b'
    value: string
}

type Param = AParam | BParam;

const p: Param = {
  key: 'a',
  value: '', // error
}

This is the only approach that will work if you need the variable p to be able to hold either key, but still have the value be the correct type.

You can reach this goal with the help of mapped types.

type ParamHelper<T> = { [K in keyof T]: { key: K; value: T[K] } };
type Param<T> = ParamHelper<T>[keyof ParamHelper<T>];

type param<o> = {
    [k in keyof o]: {
        key: k,
        value: o[k]
    }
}[keyof o];
const o = {a:1, b:2} as const
const a: param<typeof o> ={
    key:'a',
    value:1
}
Related