Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unknown type is narrowed to {} in strict equality condition since 4.8 #50567

Closed
43081j opened this issue Aug 31, 2022 · 7 comments · Fixed by #50601
Closed

unknown type is narrowed to {} in strict equality condition since 4.8 #50567

43081j opened this issue Aug 31, 2022 · 7 comments · Fixed by #50601
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@43081j
Copy link

43081j commented Aug 31, 2022

Bug Report

🔎 Search Terms

narrowing, object type, unknown, unknown narrowing

🕗 Version & Regression Information

  • This changed between versions 4.7.x and 4.8.x
  • Happens in nightly (4.9.x)

⏯ Playground Link

Playground link with relevant code

💻 Code

const foo = (value: unknown): string => {
    if (!value) {
        return 'foo';
    }
    if (value === 'xyz') {
        return value; // Type '{}' is not assignable to type 'string'.
    }
    return '';
};

// This one compiles fine
const bar = (value: unknown): string => {
    if (value === 'xyz') {
        return value;
    }
    return '';
};

🙁 Actual behavior

Type '{}' is not assignable to type 'string'.

Even though we've clearly inferred that the unknown is literally the string "xyz", the compiler somehow thinks it is instead {}.

🙂 Expected behavior

Builds fine.

More info

You can see here that its specific to having the false-check at the start of the function.

Removing the if(!value) condition causes the code to compile as expected.

So it seems that turns the value into {} somehow.

@fatcerberus
Copy link

Related: #50531

@andrewbranch
Copy link
Member

I would have definitely marked this as a duplicate of #50531 if we hadn’t just traced #50531 to some code specific to the in operator...

[panda_smashing_computer.gif]

@andrewbranch andrewbranch added the Bug A bug in TypeScript label Sep 1, 2022
@andrewbranch andrewbranch added this to the TypeScript 4.8.3 milestone Sep 1, 2022
@andrewbranch
Copy link
Member

I mean, this actually makes total sense under long-standing narrowing rules plus the changes to unknown in #49119. Narrowing in most cases only happens on unions, and now unknown is equivalent to a union of {} | null | undefined. So narrowing it to {} is absolutely correct; the issue is we don’t narrow {} to "xyz", but {} has never had to do that before. Maybe it should get some of the same special-case rules that narrowing unknown already had before becoming union-like.

@fatcerberus
Copy link

I would have definitely marked this as a duplicate of #50531 if we hadn’t just traced #50531 to some code specific to the in operator...

Yeah, #50531 is a weirder issue where the narrowing behavior for {} actually differs depending on whether it's a direct {} or came from narrowing unknown.

@andrewbranch
Copy link
Member

Yeah, this one is way less weird at second glance. I turned on the ability to narrow straight from {} to a primitive under strict equality the same way unknown does before writing a test, and no existing baselines changed 😳

@fatcerberus
Copy link

now unknown is equivalent to a union of {} | null | undefined

I'm going to hope this isn't reflected under conditional type distribution the same way boolean is true | false because that sounds like a huge breaking change...

@andrewbranch
Copy link
Member

Sorry, did I say “equivalent”? I meant ✌️EQUIVALENT✌️***™️

* NOT ACTUALLY EQUIVALENT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants