Skip to content

Union types are not expanded properly when checking if type satisfies generic constraint #49778

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

Closed
jabuj opened this issue Jul 4, 2022 · 6 comments Β· Fixed by #52668
Closed
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@jabuj
Copy link

jabuj commented Jul 4, 2022

Bug Report

πŸ”Ž Search Terms

Union types expansion, generic constraints

πŸ•— Version & Regression Information

4.6, works fine in 4.5

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type UnionType = {name: 'A'} | {name: 'B'}
type NotUnionType = {name: 'A' | 'B'}

type MyType<T extends UnionType> = number
// Errors here, because NotUnionType is presumably not assignable to UnionType
let d: MyType<NotUnionType>

// No error, because NotUnionType is assignable to UnionType
let check: NotUnionType extends UnionType ? true : false 
    = true

The error doesn't reproduce, however, if I change the order of lines:

let check: NotUnionType extends UnionType ? true : false 
    = true
// No error
let d: MyType<NotUnionType>

πŸ™ Actual behavior

Error when instanciating MyType<NotUnionType>

πŸ™‚ Expected behavior

No error. Also error trace seems to be missing some entries in the beginning (I would expect it to start with something like NotUnionType does not satisfy the constraint UnionType whereas in actuality is starts with Type 'NotUnionType' is not assignable to type '{ name: "B"; }').

@jabuj
Copy link
Author

jabuj commented Jul 4, 2022

If it's indeed a bug, a temporary workaround could be something like

let d: MyType<NotUnionType extends UnionType ? NotUnionType : never>

The extends clause always evaluates to true, and apparently the cached result that NotUnionType is assignable to UnionType lets bypass the error

@fatcerberus
Copy link

fatcerberus commented Jul 4, 2022

This looks like two bugs, actually:

  1. What seems like a caching bug, as you note
  2. NotUnionType extends UnionType should not be true. In general { x: T | U } is not assignable to { x: T } | { x: U } (but the inverse is okay), and extends in this context means "is assignable to"

edit: I stand corrected on point 2. See Ryan's comment immediately below.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Jul 5, 2022
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.8.1 milestone Jul 5, 2022
@RyanCavanaugh
Copy link
Member

{ name: "A" | "B" } is assignable to { name: "A" } | { name: "B" } in cases where the total number of possible constituents in the right side is small (I believe it's 24 or under) and also literal types.

Changing error arity based on the order of lines is definitely a bug, though.

@fatcerberus
Copy link

fatcerberus commented Jul 5, 2022

In that case, repro:

type AObjOrBObj = { name: "A" } | { name: "B" };
type AOrBObj = { name: "A" | "B" };
type Generic<T extends AObjOrBObj> = T;

type T = Generic<AOrBObj>;  // error if here

declare let x: AObjOrBObj;
declare let y: AOrBObj;
x = y;  // ok
y = x;  // also ok

//type T = Generic<AOrBObj>;  // not an error if here

@jakebailey
Copy link
Member

jakebailey commented Jul 6, 2022

I was hoping this would be fixed by #49718 (because if you have type T = ... at the bottom, then comment out the assignments, they aren't related, and the behavior changes), but that doesn't seem to be the case.

@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Feb 1, 2023
@jakebailey
Copy link
Member

It turns out that it was in fact fixed by #49718; not sure how I managed to make it fail in my comment above. Will send a PR which adds a test.

@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Feb 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants