For my app I used a "Discriminated Union" pattern with exhaustiveness check as described in the TypeScript manual. Time went by, and eventually my switch ended up containing 50+ cases.
So my question is: is there any good solution to decompose this switch without braking its exhaustiveness?
In other words how to split it up, if this can help I can logically divide these unions on subtypes (for ex. shapes below can be divided for equilateral and others):
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
//... 50 more shape kinds
type Equilateral = Square | Circle /*| 25 more...*/;
type Other = Rectangle /*| 25 more...*/;
type Shape = Equilateral | Other;
function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.height * s.width;
case "circle": return Math.PI * s.radius ** 2;
/*
...
... a lot of code lines
...
*/
default: return assertNever(s);
}
}
I just found out (through experimentation, not because it's mentioned in documentation anywhere) that you can indeed build a type hierarchy of discriminated unions using multiple discriminants:
interface Square {
shape_kind: "equilateral";
kind: "square";
size: number;
}
interface Circle {
shape_kind: "equilateral";
kind: "circle";
radius: number;
}
interface Rectangle {
shape_kind: "rectangle";
width: number;
height: number;
}
type Equilateral = Square | Circle
type Shape = Equilateral | Rectangle;
function area(s: Shape) {
switch (s.shape_kind) { // branch on "outer" discriminant
case "equilateral":
// s: Equilateral in here!
return area_root(s) ** 2;
case "rectangle":
return s.height * s.width;
}
}
function area_root(e: Equiliteral) {
switch (s.kind) { // branch on "inner" discriminant
case "square": return s.size;
case "circle": return Math.sqrt(Math.PI) * s.radius;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With