typescript-go
typescript-go copied to clipboard
`UnionToTuple` type returns "inverted" tuple in TSGO compared to TypeScript 5.8.3 and gives type error
Hello,
This will need a little investigation (learning the type-fest package types), but I tried running TSGO in my current project and got some errors. Basically, type-fest has a UnionToTuple type and TSGO inverts the tuple values and gives an error. TSGO successfully extracts the union values and makes them into a tuple, but reversed compared to TypeScript 5.8.3.
Testable repo: https://github.com/alexwork1611/tsgo-union-to-tuple.
Hope it helps.
Thanks!
Union ordering is undefined, determined only by the implementation details of the checker. The Go code isn't the same as the previous compiler (in order to handle concurrency) and uses a different but deterministic sort order, intentionally. Anything like "union to tuple" is going to behave differently.
Union ordering is undefined, determined only by the implementation details of the checker. The Go code isn't the same as the previous compiler (in order to handle concurrency) and uses a different but deterministic sort order, intentionally. Anything like "union to tuple" is going to behave differently.
Thanks for your answer. Shouldn't this be something that's standardized, though?
What does "this" refer to, and what do you mean by "standardized"?
Good clarifying question. "This" refers to the way unions are sorted. "Standardized" refers to the idea that the two compilers should be intentionally designed to have matching union element sorting.
They can't be; the old method was dependent on the order of files and the order that the checker walks everything. There was no "design", per se.
In the new compiler, we check files concurrently, which means we are going to be doing everything in entirely different orders, have errors that change each time the code is checked, etc, if we aren't careful. Hence, we have more strictly defined ordering to not be in terms of type IDs.
The ordering calculation is not free; it's not good for perf in the old codebase: https://github.com/microsoft/TypeScript/pull/61399
I'll note that it's always been dubious to depend on union order for anything; simple changes like swapping the order of two declarations in the same file, sorting your imports, etc, could all affect the behavior, which isn't great.
We tried our best to tell people not to do this, but some folks are very determined to do dangerous things.
See also
https://github.com/microsoft/TypeScript/issues/13298#issuecomment-468481350
https://github.com/microsoft/TypeScript/issues/13298#issuecomment-493583406
Thank you so much, @RyanCavanaugh and @jakebailey. I refactored my code and I am not using the UnionToTuple type anymore.
The reason why I went for that is because I wanted to enforce the my types into my runtime, but I was able to come up with an alternative. Here is the before and after (for one of the places that were giving me errors because of the tuple elements order):
Before:
After:
Here are the UserRole definitions:
I hope the images above provide insight into my thinking and I hope you can empathize with me not knowing the things discussed in the awesome PR mentioned by @jakebailey and @RyanCavanaugh's reply above.
Thanks again!
For what it's worth the reason why it was never a good idea is to look at a snippet of code like this:
import { UnionToTuple } from "type-fest";
// Try commenting and uncommenting this line:
declare const b: "b";
type Test = UnionToTuple<"a" | "b">;
When it's uncommented you'll get ["b", "a"]. When it's commented you'll get ["a", "b"]. Imagine just happening to add "Guest" anywhere else in your code (maybe even in a random dependency!) and suddenly it jumps to the front. It might not even be "consistent" because in editor it'll walk files differently than with a full rebuild.