Skip to content

tsc gets confused on checking assignability with numeric literals? #44087

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

Closed
h-joo opened this issue May 14, 2021 · 5 comments
Closed

tsc gets confused on checking assignability with numeric literals? #44087

h-joo opened this issue May 14, 2021 · 5 comments
Labels
Won't Fix The severity and priority of this issue do not warrant the time or complexity needed to fix it

Comments

@h-joo
Copy link
Contributor

h-joo commented May 14, 2021

Bug Report

TSC reports This condition will always return 'false' since the types 'A' and '-1' have no overlap.

For a moment I thought this might be another instance of #9998 or #8513, but from my understanding, the compiler ignores the -1 from the union type annotation of abc(A | -1) in , because number is not assignable to -1. So I thought this might be a different issue from #9998 or #8513, since the core issue seems to be that a literal type within a union expression gets ignored.

🔎 Search Terms

🕗 Version & Regression Information

Started to appear from 4.3.0-beta

⏯ Playground Link

Playground link

💻 Code

enum A{
    A0 = 0,    
    A1 = 1,
}
function foo(param:number) {
    const abc : (A | -1) = param;
    if(abc === -1) {
       ~~~~~~~~~ This condition will always return 'false' since the types 'A' and '-1' have no overlap.        
    }
}

🙁 Actual behavior

TSC complains that abc cannot be -1

🙂 Expected behavior

TSC is happy

@h-joo h-joo changed the title This condition will always return 'false' since the types have no overlap tsc gets confused on checking assignability with numeric literals? May 14, 2021
@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label May 14, 2021
@RyanCavanaugh
Copy link
Member

This seems likely to be a side effect of having fixed #42442.

@RyanCavanaugh
Copy link
Member

cc @ahejlsberg and @DanielRosenwasser for ideas on how to fix this 😕

@ahejlsberg
Copy link
Member

Ugh. We permit the assignment of number to A | -1 because, for ancient backwards compatibility reasons, number is assignable to any numeric enum type. Control flow analysis then narrows abc by removing all non-assignable types from its union type, thus believing abc has type A following the initialization. And that type doesn't include -1 so CFA now thinks the condition is always false.

We need to somehow exclude the number-assignable-to-any-enum rule from our control flow analysis. Ideally CFA sould view the initialization as having an unknown effect, thus not narrowing at all following the initialization.

@RyanCavanaugh
Copy link
Member

I would honestly propose Won't Fix and recommend writing

    const abc = param as (A | -1);

instead since the assignment is already unsound.

Piling up the epicycles higher will probably only make things worse.

@RyanCavanaugh RyanCavanaugh added Won't Fix The severity and priority of this issue do not warrant the time or complexity needed to fix it and removed Bug A bug in TypeScript labels May 14, 2021
@RyanCavanaugh
Copy link
Member

The disallowment of abc === -1 is a documented breaking change.

Fixing the narrowing would be very invasive and noisy; we're going to leave this as-is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Won't Fix The severity and priority of this issue do not warrant the time or complexity needed to fix it
Projects
None yet
Development

No branches or pull requests

3 participants