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

Ternary results consider both branches even when boolean literal values make one impossible #14206

Closed
krryan opened this issue Feb 21, 2017 · 2 comments
Labels
Question An issue which isn't directly actionable in code Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@krryan
Copy link

krryan commented Feb 21, 2017

TypeScript Version: 2.3.0-dev.20170217

Code

const aOrB = true ? 'a' : 'B';
const a: 'a' = aOrB;

Expected behavior:
Compiles without error.

Actual behavior:

Type '"a" | "B"' is not assignable to type '"a"'.
Type '"B"' is not assignable to type '"a"'.

@vladima
Copy link
Contributor

vladima commented Feb 21, 2017

Currently reachability analysis in compiler works on the statement level which has a good rationale: it is pretty common to have code like while(true) <block> where control flow inside the loop can be abrupted via return, break, continue or throw statements. However having it on the expression level add a very little value to the real world use-cases, i.e. what is the purpose of writing code like true ? <do-something> : <do-something-else> other than making synthetic example?

@vladima vladima added Question An issue which isn't directly actionable in code Working as Intended The behavior described is the intended behavior; this is not a bug labels Feb 21, 2017
@krryan
Copy link
Author

krryan commented Feb 21, 2017

I generally feel like the compiler should be as aware of types as possible. This is obvious using true itself, but when using a function that returns true, or particularly an overload the returns true with a particular input, would be less obvious, and thus something like this could result in improved error-checking in the face of refactoring.

For example:

const foobar = passesSomePredicate(foo) ? new Foo() : new Bar();
if (isFoo(foobar)) {
    doSomethingWithFoo(foobar);
}
else {
    doSomethingWithBar(foobar);
}

When originally written, presumably this code was meaningful. But suppose some refactoring happened that caused bar to be narrower, or an overload for passesSomePredicate was written, and either way, now we have passesSomePredicate(typeof foo): true. This means that foobar must be a Foo (and not a Bar), which means isFoo (a typeguard) is redundant and the else block is unreachable. If the compiler knew that foobar had to be a Foo and that else block is unreachable and the value of foobar in doSomethingWithBar(foo) is never. It improves the compile-time understanding of the system, and can help find redundant or unreachable code.

@mhegazy mhegazy closed this as completed Apr 24, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

3 participants