Skip to content

Inconsistent subtyping between union of objects and object with union property when the number of variants > 25 #51677

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
tsuburin opened this issue Nov 29, 2022 · 4 comments

Comments

@tsuburin
Copy link

Bug Report

πŸ”Ž Search Terms

object union subtyping

πŸ•— Version & Regression Information

  • This changed between versions v3.3.3 and v3.5.1

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

The exact same code with that of playground above.

type X25 =
  1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25
type X26 = X25 | 26

type Y25 =
  | { x: 1 }
  | { x: 2 }
  | { x: 3 }
  | { x: 4 }
  | { x: 5 }
  | { x: 6 }
  | { x: 7 }
  | { x: 8 }
  | { x: 9 }
  | { x: 10 }
  | { x: 11 }
  | { x: 12 }
  | { x: 13 }
  | { x: 14 }
  | { x: 15 }
  | { x: 16 }
  | { x: 17 }
  | { x: 18 }
  | { x: 19 }
  | { x: 20 }
  | { x: 21 }
  | { x: 22 }
  | { x: 23 }
  | { x: 24 }
  | { x: 25 }
type Y26 = Y25 | {x: 26}

type TestXY25 = {x: X25} extends Y25 ? true: false // true
type TestXY26 = {x: X26} extends Y26 ? true: false // false <--

type TestYX25 = Y25 extends {x: X25} ? true: false // true
type TestYX26 = Y26 extends {x: X26} ? true: false // true

πŸ™ Actual behavior

Type {x: T1 | ... | TN} is not treated as a subtype of {x: T1} | ... | {x: TN} when N > 25

πŸ™‚ Expected behavior

It should be treated as a subtype. Or at least, the behavior should not change between N <= 25 and N > 25

@tsuburin tsuburin changed the title inconsistent subtyping between union of objects and object with union property when the number of variants > 25 Inconsistent subtyping between union of objects and object with union property when the number of variants > 25 Nov 29, 2022
@fatcerberus
Copy link

Type {x: T1 | ... | TN} is not treated as a subtype of {x: T1} | ... | {x: TN} when N > 25

See e.g. #43283. It's an intentional tradeoff for performance reasons because this comparison involves a potentially combinatorially explosive expansion in the general case.

@tsuburin
Copy link
Author

@fatcerberus Thank you. Is this behavior documented somewhere?

@fatcerberus
Copy link

fatcerberus commented Nov 29, 2022

The GitHub issues are considered to be part of the documentation. Beyond that, I suspect it’s not documented because it’s considered a design limitation (i.e. subject to removal or relaxation if a way to do so without hurting performance is found) and the mechanism itself is a bit tricky to explain: the limit of 25 types applies to the number of types in the expansion, so for example { x: "a" | "b", y: "c" | "d" } is expanded to 4 types (one for each pair of possible strings) which is under the limit and thus assignable to the union of those types but { x: "a" | "b" | "c", y: "d" | "e" | "f", z: "g" | "h" | "i" } is over the limit because it expands to a union of 3 * 3 * 3 = 27 types.

As for why it works when n < 25 instead of consistently being an error: TS generally goes out of its way to allow simple cases to work even in the face of design limitations.

@tsuburin
Copy link
Author

Thank you for the detailed explanation. I understood.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants