Разветвление кода на основе типов интерфейсов, расширяющих - PullRequest
0 голосов
/ 28 апреля 2018

У меня есть несколько интерфейсов, которые расширяются от базы:

enum eItemType { /* … */ }

interface Item {
    someCommonKeyValPairCollection: eItemType;
    type: eItemType;
    weight: number;
    // …
}

interface ItemTypeA extends Item {
    someKeyValPairCollection: eItemType;
}

interface ItemTypeB extends Item {
    someOtherKeyValPairCollection: eItemType;
}

type tItem = Item | ItemTypeA | ItemTypeB

И затем у меня есть метод, который получает Item, но это может быть универсальный (не ключевое слово) Item или ItemTypeA или ItemTypeB, поэтому я создал тип объединения tItem. Метод делает некоторые общие вещи, а затем некоторые определенные вещи, основанные на item.type (циклически проходя либо someKeyValPairCollection, либо someOtherKeyValPairCollection. Typescript сходит с ума, выбрасывая полдюжины ошибок присваивания, например Property 'someKeyValPairCollection' is missing in type Item (без дерьма).

Метод выглядит примерно так:

processItem(item: tItem): boolean {
    const isValid: boolean = checkValidity(item);
    if (!isValid) return false;

    _.each(someCommonKeyValPairCollection, () => { /* do some common stuff */ });

    // if (typeof item.someKeyValPairCollection !== 'undefined') // tried first, doesn't like
    if (item.type === eItemType.a) processA(item.someKeyValPairCollection);

    return true;
}

Как справиться с if (item.type === eItemType.a) // do some special stuff?

1 Ответ

0 голосов
/ 28 апреля 2018

Вам необходимо использовать дискриминационный союз. Объединение, в котором одно свойство (в данном случае type) имеет конкретное значение для определенного типа. Вы можете прочитать больше о теме здесь

enum eItemType {
    a, b, c
}

interface Item {
    someCommonKeyValPairCollection: eItemType;
    type: eItemType;
    weight: number;
    // …
}
interface ItemTypeA extends Item {
    type: eItemType.a
    someKeyValPairCollection: eItemType;
}

interface ItemTypeB extends Item {
    type: eItemType.b
    someOtherKeyValPairCollection: eItemType;
}

interface ItemTypeOther extends Item {
    type: Exclude<eItemType, eItemType.a | eItemType.b>
}


type tItem = ItemTypeA | ItemTypeB | ItemTypeOther
function processItem(item: tItem): boolean {
    if (item.type === eItemType.a) {
        item.someKeyValPairCollection
    }
    else if (item.type === eItemType.b) {
        item.someOtherKeyValPairCollection
    } else {
        item  // will be ItemTypeOther
    }
    return true;
}

Редактировать

Добавлена ​​простая альтернатива для перехвата остальных значений перечисления без необходимости определения отдельного типа для каждого значения перечисления или необходимости перечислять их по отдельности.

...