microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.31k stars 12.53k forks source link

Unexpected "Object is possibly 'undefined'." error with a nullable key #54854

Closed alex996 closed 1 year ago

alex996 commented 1 year ago

Bug Report

🔎 Search Terms

Object is possibly 'undefined' / undefined key / nullable key

🕗 Version & Regression Information

⏯ Playground Link

Playground link with relevant code (Nightly)

💻 Code

const food: Record<string, string[] | undefined> = {"fruits": ["apple"]};

const keys = ["vegetables", "meat", "dairy", undefined];
const randomKey = keys[Math.floor(Math.random() * keys.length)];

if (randomKey) {
    if (food[randomKey]) {
        food[randomKey].push("whatever")
    } else {
        food[randomKey] = ["whatever"];
    }
}

🙁 Actual behavior

It fails to compile with an error: Object is possibly 'undefined'.(2532).

It should compile because:

  1. We check that randomKey is truthy (I tried if (randomKey !== undefined) { but got the same error)
  2. We check that food[randomKey] is truthy (I tried if (food[randomKey] !== undefined) { but got the same error)
  3. The resulting JavaScript code executes without a runtime error.

🙂 Expected behavior

It should compile without errors.

MartinJohns commented 1 year ago

Duplicate of #10530. Type narrowing does not occur for indexed access forms e[k] where k is not a literal. Just store it in a local const variable.

alex996 commented 1 year ago

Apologies for the duplicate. I suspected it was going to be a long-standing issue.

If this a common enough problem, please consider adding it to the FAQ if it fits there.

Here's the fix as suggested (and with the playground)

if (randomKey) {
    const arr = food[randomKey];
    if (arr) {
        arr.push("whatever")
    } else {
        food[randomKey] = ["whatever"];
    }
}