Earlier quoted context omitted.
Not who you asked (and I just now realized I'm replying to you twice regarding this OP, I solemnly swear it's not some crude attempt at stalking). But for me the main use for TS union types is to make discriminated unions, which is very useful wherever you have some form of a state-machine: type AppState = | { state: "loading", progress: number } | { state: "selecting_level", } | { state: "playing", level: Level } |…
Haha. That's alright. That looks super neat though, I must admit. The only equivalent that comes to mind would be using an abstract class. I still might fail to fully understand what that code example does, but, would this be somewhat similar? abstract class AppState {} class AppLoading extends AppState { final int progress; } class AppSelectingLevel extends AppState {} class AppPlaying extends AppState { final Level…
Unless I'm mistaken, if one were to later implement a new class that extends AppState, all existing code would compile, but possibly fail or misbehave at runtime, unless you meticulously checked every place that tries to determine something based on those derived types.
In TypeScript, adding a new case for an union and not handling it everywhere is a compilation error on every incomplete usage site.
For example, try deleting one of the arms of the switch in this playground: https://www.typescriptlang.org/play?ts=4.2.2#code/C4TwDgpgBA...
I have to say, the default diagnostic isn't brilliant, but some tooling will give a better error and actually point out the missing arms, instead of complaining about the return type.