Microsoft/TypeScript

Assignment narrowing failing to reset in a loop with optional chaining

Open

#57,816 opened on Mar 17, 2024

View on GitHub
 (3 comments) (1 reaction) (0 assignees)TypeScript (6,726 forks)batch import
BugDomain: check: Control FlowHelp Wanted

Repository metrics

Stars
 (48,455 stars)
PR merge metrics
 (Avg merge 6d 17h) (9 merged PRs in 30d)

Description

🔎 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).

Contributor guide