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

0

Issue

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)?

Solution

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

Answered By – Aleksey L.

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave A Reply

Your email address will not be published.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More