Skip to content

In overload resolution, any always matches the first of true or false, never boolean #46376

@dgoldstein0

Description

@dgoldstein0

Bug Report

🔎 Search Terms

control flow analysis
function overrides

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about it.
  • I discovered it on 4.0.7 and verified on 4.0.5 and 4.4.4

⏯ Playground Link

Playground link with relevant code

💻 Code

const nonempty: Function = (s: string) => s.length != 0;

function assert(cond: boolean, msg: string) : void;
function assert(cond: false, msg: string) : never;
function assert(cond: boolean, msg: string) {
    if (!cond) throw new Error(msg);
}

const d = nonempty("foo");
assert(d, "hi");
for (const x of ["a", "b", "c"]) {
    nonempty("bar");
}

🙁 Actual behavior

nonempty is narrowed to never after the assert()
The for loop is labeled as unreachable code in the typescript playground (but not by tsc - going to file that as a separate issue)

It appears that typing nonempty as a Function makes the return any, and that doesn't match the right overload of assert - for whatever reason it always matches the assert(cond: false, msg:string) case which returns never and therefore concludes, erroneously, that the rest of the code is unreachable.

🙂 Expected behavior

expect no errors - the assert(cond: boolean, msg: string): void signature should match and so typescript should not be able to assume code after the assert() call is unreachable. Perhaps the typesafe way to do this would be unioning all the possible return types.

Edit by @sandersn: See #46376 (comment) for a smaller repro

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions