Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if a strongly typed object contains a given key in TypeScript without it complaining?

Tags:

typescript

Take this code:

const lookup = {
    foo: 1,
    bar: 2
}

const getValueOrDefault = (name: string, defaultValue: number) => {
    if (name in lookup) {
        return lookup[name] // ERROR
    }

    return defaultValue
}

The lookup[name] expression causes this TS error (playground):

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ foo: number; bar: number; }'.
  No index signature with a parameter of type 'string' was found on type '{ foo: number; bar: number; }'.

...even though I did if (name in lookup) to check it first. I tried hasOwnProperty, and that doesn't work either.

TypeScript is often smart about refining types within conditional blocks, but not here. Why? And how can I make it work (without just hacking it by relaxing the type of lookup)?

like image 465
callum Avatar asked Dec 17 '22 15:12

callum


1 Answers

You can wrap the name in lookup check in type guard to help typescript to understand that once condition is true - name is valid lookup's key:

const getValueOrFalse = (name: string) => {
    if (isObjKey(name, lookup)) {
        // name narrowed to "foo" | "bar"
        return lookup[name]
    }

    return false
}

function isObjKey<T>(key: PropertyKey, obj: T): key is keyof T {
    return key in obj;
}

Playground

like image 132
Aleksey L. Avatar answered May 28 '23 00:05

Aleksey L.