Search code examples
typescripttypeguards

How to assert a value is a valid key without knowing the object keys at compile-time?


In TypeScript, is there any way to declare that a variable is a keyof some Record without knowing what the keys of the Record are?

Assume an API response returns a payload of JSON. I want to define a type for the keys of the payload so I can index through the payload and know that the value will not be undefined. Is this possible or do I have to simply check for undefined every time I index the payload object?

Example:

const payload: Record<string, ValidValue> = await myApiCall()

const prop1 = 'a'
const prop2 = 'b'

if (isValidKey(prop1, payload)) {
  const value1 = payload[prop1] // the type of `value1` should evaluate to `ValidValue`
}

const value2 = payload[prop2] // the type of `value2` should evaluate to `ValidValue | undefined`

Solution

  • I got it to work using a type guard function as well, but not returning key is keyof MyMap. Instead, I had a type for the payload object of Record<string, ValidValue | undefined> and then the type guard returns payload is Record<K, ValidValue> where K is the type of the key param.

    You can play with it on TS Playground.

    // Type alias for convenience
    type Payload = Record<string, ValidValue | undefined>;
    
    const payload: Payload = await myApiCall()
    
    function isValidKey<K extends string>(key: K, payload: Payload): payload is Record<K, ValidValue> {
      return key in payload;
    }
    
    const prop1 = 'a'
    const prop2 = 'b'
    
    if (isValidKey(prop1, payload)) {
      const value1 = payload[prop1] // the type of `value1` should evaluate to `ValidValue` ✅
    }
    
    const value2 = payload[prop2] // the type of `value2` should evaluate to `ValidValue | undefined` ✅