I think that union types allow something that sealed classes don’t: they’re able to represent SUBSETS of classes with a common ancestor or interface. Even subsets of enumerations, if their behaviour is extended.
For example, consider these classes:
interface Athlete {
}
class FootballPlayer : Athlete {
}
class Swimmer : Athlete {
}
class BasketballPlayer : Athlete {
}
// Etc.
A specific method might want to return instances of only some of those implementations:
typealias BallPlayer = FootballPlayer | BasketballPlayer;
...
fun findPlayersOfBallSports (): BallPlayer {
}
...
let player: BallPlayer = findPlayersOfBallSports ();
if (player instanceof Swimmer) {
// ^^^ Error!!! Because "player" can only be an instance of either
// FootballPlayer or BasketballPlayer.
}
In my opinion, it makes the code be much more powerful and self-documented.
If this behaviour were extended to instances of enum
, it would also allow things like this:
enum class Device {
SCREEN,
KEYBOARD,
MOUSE,
CPU,
RAM,
DISK;
}
...
typealias InputDevice = Device.KEYBOARD | Device.MOUSE;
...
fun getInputDevices (): InputDevice {
}
...
let device: InputDevice = getInputDevices ();
if (device == Device.CPU) {
// ^^^ Error!!! Because "device" can only be either
// Device.KEYBOARD or Device.MOUSE.
}