Home > front end >  Typescript allowing access to an undefined object property
Typescript allowing access to an undefined object property

Time:11-04

I'm trying to access keys from an object via a function, and if the value doesn't exist, check the next object. I understand the error, but I'm not sure how to handle this situation properly, for example allowing TS to access a missing property.

// constants with transformed values
const firstList = { foo: "a value" }
const secondList = { bar: "another value" }

function getValue( key: keyof typeof firstList | keyof typeof secondList ) {
    let val = firstList[key]
    if (val != undefined) return val
    return secondList[key]
}

Element implicitly has an 'any' type because expression of type '"foo" | "bar"' can't be used to index type '{ foo: string; }'. Property 'bar' does not exist on type '{ foo: string; }'.

CodePudding user response:

Consider changing your implementation, and adding a type guard:

// check if key is in the value and narrows the type of `key`
function isKeyIn<K extends keyof T, T>(key: K, value: T): key is keyof T & K {
    return key in value;
}

function getValue( key: keyof typeof firstList | keyof typeof secondList ) {
    // if statement with early return would also work
    return isKeyIn(key, firstList) ? firstList[key] : secondList[key];
}

See type predicates in the handbook.

Playground

CodePudding user response:

Consider this:

// constants with transformed values
const firstList = { foo: "a value" }
const secondList = { bar: "another value" }

const isAllowedKey = <Obj extends Record<PropertyKey, unknown>>(obj: Obj, prop: PropertyKey)
    : prop is keyof Obj =>
    Object.prototype.hasOwnProperty.call(obj, prop);


function getValue(key: keyof typeof firstList | keyof typeof secondList) {

    if (isAllowedKey(firstList, key)) {
        let val = key

        if (val != undefined) {
            return val
        }
    } else {
        return secondList[key]

    }

    // We should cover all pathes
    return undefined
}

Playground

As you might have noticed, I have added third path: return undefined, this is because in order to infer bar key, you need to put it into else branch. However with if\else we ended up in a situation when return undefined is not reachable but TS complains about covering all pathes

  • Related