Microsoft/TypeScript

Assignment narrowing failing to reset in a loop with optional chaining

开放

#57,816 创建于 2024年3月17日

 (3 条评论) (1 个反应) (0 位负责人)TypeScript (13,395 个派生)batch import
BugDomain: check: Control FlowHelp Wanted

仓库指标

星标
 (108,860 个星标)
PR 合并指标
 (PR 指标待抓取)

描述

🔎 Search Terms

assignment narrowing, optional chaining, narrowing to never,

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about assignment narrowing and optional chaining.

⏯ Playground Link

Playground link

💻 Code

interface Foo { bar: number; }
declare const foos: Foo[];
let prevPrevFoo: Foo | null = null;
let prevFoo: Foo | null = null;
for (const foo of foos) {
  while (
    foo.bar === prevPrevFoo?.bar && // error!
    // --------------------> ~~~
    // Property 'bar' does not exist on type 'never'.
    foo.bar === prevFoo?.bar
  ) {
    foo.bar++
  }
  prevPrevFoo = prevFoo;
  prevFoo = foo;
}

🙁 Actual behavior

prevPrevFoo is apparently narrowed to null via assignment narrowing, so prevPrevFoo?.bar gives an error that never doesn't have a bar property. But prevPrevFoo is assigned within the loop, so it seems strange that the narrowing persists in that scope.

🙂 Expected behavior

No error, prevPrevFoo should be considered Foo | null inside the loop.

Additional information about the issue

Comes from this SO question. Not sure what's going on here, but it seems quite dependent on the nesting and order of operations. Most things I did to try to reduce it further made the error disappear.

Note that this is not a case of #9998, there's no closure to speak of. And of course we can work around this by opting out of assignment narrowing via let prevPrevFoo = null as Foo | null;. I don't think this is a big deal, but it would be nice to know the cause of this and whether it's a bug, design limitation, or somehow working as intended (and if so, why).

贡献者指南