как декомпозировать блок переключателей TypeScript «Дискриминационный союз» и в то же время сделать его исчерпывающим - PullRequest
0 голосов
/ 28 января 2019

Для своего приложения я использовал шаблон «Дискриминационное объединение» с проверкой исчерпываемости, как описано в руководстве по TypeScript .Прошло время, и в итоге мой коммутатор в конечном итоге содержал более 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); 
    }
}

1 Ответ

0 голосов
/ 28 января 2019

Я только что выяснил (в результате экспериментов, а не потому, что это упоминается в документации где-либо), что вы действительно можете построить иерархию типов различающихся объединений, используя множественные дискриминанты :

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...