Skip to content

Incorrect narrowing of boolean type when variable is mutated in a timerΒ #61445

@TAGraves

Description

@TAGraves

πŸ”Ž Search Terms

"no-unnecessary-condition", "boolean", "constant", "mutated", "conditional", "timer"

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about setTimeout

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.9.0-dev.20250318&ssl=9&ssc=1&pln=1&pc=1#code/KYDwDg9gTgLgBDAnmYcCSBnAoiAhgYxgB4AVAGjgFUA+OAXjgG0SBdOUGYAOwBMMnKbAPxwAFI0HsQnXv2bCEUAK6oAXHABmuADYZgASjjqtu4AG4AUKEixNSroQCWELnFwY9sEsmCkpMvkUVOAAfTR09alEAfXUSQwBvAF8LC21geAAjCAhtenDTSz0YEkcAW2AIJRhRUUM6WgS4bNz8mGVzOCSKAEZ9SwtcAHdcR3guYCG4AAUoCDLHPVEoYAxcgDdUBrhi0oqqmrr6WhW17U3Rex5gDUcJnn1egAYn-X7Bj2AvHyJMHAJiEgUBANM0ctoKCZIlEoQZLEA

πŸ’» Code

export type IsExact<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;
export function assertType<T extends true | false>(_: T) {}

let bool = false;
setTimeout(() => { bool = true; }, 1);

await new Promise(resolve => setTimeout(() => resolve(undefined), 100));
assertType<IsExact<typeof bool, false>>(false);

πŸ™ Actual behavior

Argument of type 'false' is not assignable to parameter of type 'true'. In this case, that means that bool is narrowed to false on line 8.

πŸ™‚ Expected behavior

The type of bool should be boolean because it will be true if the timer on line 5 ran and false if it did not. (In practice, with this exact code snippet, it is always true, so it definitely should not be narrowed to false!)

Additional information about the issue

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions