如何分解 TypeScript "Discriminated Union" switch 块并同时保持它的详尽性

how to decompose TypeScript "Discriminated Union" switch block and keep it exhaustive at the same time

对于我的应用程序,我使用了 "Discriminated Union" 模式,并按照 TypeScript manual 中的描述进行了详尽检查。 时间流逝,最终我的 switch 包含了 50 多个案例。

所以我的问题是:有什么好的解决方案可以在不阻止其穷举的情况下分解这个开关?

换句话说,如何拆分它,如果这有帮助,我可以在逻辑上将这些并集划分为子类型(例如,下面的形状可以划分为等边形状和其他形状):

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); 
    }
}

我刚刚发现(通过实验,不是因为它在任何地方的文档中都提到过)你确实可以使用 多重判别式构建一个 类型层次结构 的可区分联合:

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;
    }
}