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

Type Narrowing for discriminated unions not narrow enough #12955

Closed
stevekane opened this issue Dec 15, 2016 · 2 comments
Closed

Type Narrowing for discriminated unions not narrow enough #12955

stevekane opened this issue Dec 15, 2016 · 2 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@stevekane
Copy link

stevekane commented Dec 15, 2016

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?

@ahejlsberg
Copy link
Member

ahejlsberg commented Dec 15, 2016

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.

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Dec 15, 2016
@stevekane
Copy link
Author

stevekane commented Dec 16, 2016

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
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