Skip to content

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

Closed

Description

@krryan

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"'.

Activity

  1. vladima commented on Feb 21, 2017

    @vladima
    Contributor

    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?

  2. added
    QuestionAn issue which isn't directly actionable in code
    Working as IntendedThe behavior described is the intended behavior; this is not a bug
    on Feb 21, 2017
  3. krryan commented on Feb 21, 2017

    @krryan
    Author

    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.

  4. locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in codeWorking 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