Skip to content

TS2454 after assigning a value from an exhaustive switch statement #18362

Closed

Description

@Firehed

TypeScript Version: 2.4.2

Code

enum Level {
  One,
  Two,
}

const doSomethingWithLevel = (level: Level) => {
  let next: Level;
  switch (level) {
    case Level.One:
      next = Level.Two;
      break;
    case Level.Two:
      next = Level.One;
      break;
  }
  return next; // <-- Error here
};

Expected behavior:
Since the switch statement is exhaustive over the enum, the compiler should correctly infer that next is always set and this works without error.

Actual behavior:
(16,10): error TS2454: Variable 'next' is used before being assigned.

Note: replacing the variable assignment with inline returns (e.g. case Level.One: return Level.Two;) appears to negate the problem in this instance, but that isn't an option in the code that this example was derived from since there's additional code that uses the value of next.

Activity

  1. ahejlsberg commented on Sep 10, 2017

    @ahejlsberg
    Member

    This would require the control flow analyzer to reason about dependencies between variables which is beyond its current capabilities. We're tracking a similar request in #12184. Effectively, definite assignment analysis is limited to conclusions based on the structure of the code.

  2. mhegazy commented on Sep 25, 2017

    @mhegazy
    Contributor

    Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

  3. calebsander commented on Mar 6, 2018

    @calebsander
    Contributor

    How does this require tracking dependencies between variables? It seems like the compiler should be able to reason that every code path assigns a value to next.

    Here is an example of code that similarly fails to compile:

    const A = 'A', B = 'B'
    const makeChar = () => Math.random() > 0.5 ? A : B
    const char = makeChar()
    let response: string
    if (char === A) response = '1'
    else if (char === B) response = '2'
    /*else char*/
    console.log(response) //"Variable 'response' is being used before being assigned."

    If you uncomment the else block and hover over char in it, you can see that it has type never, so the compiler is correctly inferring that that block is unreachable. In other situations where every code path assigns a value to a variable, the compiler does realize that the variable must have been assigned a value:

    const A = 'A', B = 'B'
    const makeChar = () => Math.random() > 0.5 ? A : B
    const char = makeChar()
    let response: string
    if (char === A) response = '1'
    else response = '2'
    console.log(response) //no error
  4. RyanCavanaugh commented on Mar 6, 2018

    @RyanCavanaugh
    Member

    Caleb Sander Mateos (@calebsander) there's a distinction between inference that can be done syntactically (the second example) that that which requires type analysis (the first kind).

    This is all in principle possible but we don't currently support inference that requires multiple passes that combine syntactic flow and type information. Generalizing your first example to the broadest case implies an analysis that has either an unbounded number of passes, or a completely different inference strategy.

  5. locked and limited conversation to collaborators on Jul 25, 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

    Design LimitationConstraints of the existing architecture prevent this from being fixedFixedA PR has been merged for this issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions