Skip to content

Type Narrowing for discriminated unions not narrow enough #12955

Description

@stevekane

TypeScript Version: 2.2.0-dev.20161215

Code

type Kinded
  = { kind: 0 }
  | { kind: 1 }

function forKinded ( k: Kinded ) {
  if ( k.kind == 0 ) console.log('ZERO')
  else               console.log('ONE')
}

const k = { kind: 0 }
const k2: Kinded = { kind: 0 }

forKinded(k) // nope.  it has already guessed that k is of type { kind: number }
forKinded(k2) // works.  specifying type obviously does the right thing
forKinded({ kind: 0 }) // works.  it understands that the argument literal is of type { kind: 0 }

Expected behavior:
Would expect it to try narrowing the type to a literal from the enumeration if the general enum doesn't satisfy other type expectations.
Actual behavior:
When defined as a literal function argument, typescript further narrows the type, otherwise it does not? This seems perhaps non-awesome or at least the compiler maybe ought to try further narrowing as a constraint to see if it type-checks the entirety of the program?

Activity

  1. ahejlsberg commented on Dec 15, 2016

    @ahejlsberg
    Member

    Your last example works because the object literal is contextually typed by the parameter type. But in the first const k declaration there is nothing to indicate that you want kind to have a literal type so it is widened to number. It works when you have a type annotation because you're then contextually typed, just like the function call.

    Narrowing further based on some use in another (perhaps remote) part of your program would be a non-local effect that has the potential to be very confusing (as in, why did my type all of a sudden switch to a literal type?). I don't think that is desirable.

  2. stevekane commented on Dec 16, 2016

    @stevekane
    Author

    Anders Hejlsberg (@ahejlsberg) Thanks for the response. I understand that feedback and pretty much assumed that was precisely what was happening. It seems possible to try narrowing the type being inferred to see if any narrower type satisfies the constraints of the program. I don't see how that would be "bad" behavior as if the type-checker ever manages to become fully satisfied I would see that as a win?

    Specifically in the cases where there exist valid types in scope ( literals in this case ) that are narrower than the inferred type, it seems prudent to try them. Many javascript libraries would construct these literals and then use them later in the way I have shown in this example.

  3. 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

    Working 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