Объединение перечислений в TypeScript - PullRequest
0 голосов
/ 17 июня 2020

Что было бы хорошим способом объединения нескольких перечислений в TypeScript? Моя первая интуиция подсказывала мне сделать следующее, но это создает дублирование кода, которое может привести к ошибкам.

export enum Formats {
  Shirt = 'shirt',
  Fruit = 'fruit',
}

export enum Shirt {
  Yellow = 'yellow',
  Orange = 'orange',
}

export enum Fruit {
  Orange = 'orange',
  Lemon = 'lemon',
}

export enum Item {
    ShirtYellow = 'shirt:yellow',
    ShirtOrange = 'shirt:orange',
    FruitOrange = 'fruit:orange',
    FruitLemon = 'fruit:lemon',
}

Пример использования. Перечисления используются для описания четырех различных диалогов windows. Обработчик диалога рубашки определил два диалога windows желтый и оранжевый. Диалог желтой рубашки и диалог оранжевой рубашки настолько различаются, что использовать для них диалог одного типа невозможно. Обработчик диалога рубашки не понимает диалоги фруктов. Обработчик фруктов похож, но противоположен. Существует также глобальный диспетчер диалогов, отвечающий за то, чтобы в любой момент времени было открыто только одно диалоговое окно. Глобальный оконный менеджер содержит переменную, представляющую открытый диалог. Эта переменная сохраняется на диске, чтобы сохранить состояние открытого диалога при перезагрузке приложения / страницы.

Ответы [ 2 ]

1 голос
/ 19 июня 2020

Я думаю, нам не следует сосредотачиваться на примитивных типах значений, таких как перечисления. Хорошая запись или класс могут делать то, что вы хотите. TypeScript позволяет создавать «размеченные объединения» , т.е. семейство типов, которые можно различать по одному полю («тегу»):

export enum ShirtOptions {
  Yellow = 'yellow',
  Orange = 'orange',
}

export enum FruitOptions {
  Orange = 'orange',
  Lemon = 'lemon',
}

interface Shirt {
    kind: 'shirt';
    options: ShirtOptions;
}

interface Fruit {
    kind: 'fruit';
    options: FruitOptions; // Can have a different name
}

type Format = Shirt | Fruit;

function handler(f: Format) {
    switch (f.kind) {
        case "shirt": return doShirtStuff();
        case "fruit": return doFruitStuff();
    }
}

А TypeScript выполняет проверку полноты в операторе switch и сообщит вам, если вы не обработаете все случаи (подробности см. по ссылке).

1 голос
/ 17 июня 2020

Поигравшись с этим немного, я пришел к следующему. По-прежнему существует дублирование, но, по крайней мере, есть некоторая перекрестная проверка, которая может помочь защититься от ошибок. Основная проблема заключается в том, что он довольно многословен, и можно легко забыть одну комбинацию.

type Pair<A, B> = [A, B]
const pair = <A, B>(a: A, b: B): Pair<A, B> => [a, b]

type ShirtYellow = Pair<Formats.Shirt, Shirt.Yellow>
type ShirtOrange = Pair<Formats.Shirt, Shirt.Orange>
type FruitOrange = Pair<Formats.Fruit, Fruit.Orange>
type FruitLemon = Pair<Formats.Fruit, Fruit.Lemon>

const ShirtYellow: ShirtYellow = pair(Formats.Shirt, Shirt.Yellow)
const ShirtOrange: ShirtOrange = pair(Formats.Shirt, Shirt.Orange)
const FruitOrange: FruitOrange = pair(Formats.Fruit, Fruit.Orange)
const FruitLemon: FruitLemon = pair(Formats.Fruit, Fruit.Lemon)

export type Item = ShirtYellow | ShirtOrange | FruitOrange | FruitLemon 
export const Item = { ShirtYellow, ShirtOrange, FruitOrange, FruitLemon };

Вот мои вторые попытки. На этот раз решение на основе объектов.

type AbstractItem<I extends { kind: Formats, type: any }> = I

export type ShirtItem = AbstractItem<{kind: Formats.Shirt, type: Shirt}>
export type FruitItem = AbstractItem<{kind: Formats.Fruit, type: Fruit}>

export type Item = AbstractItem<ShirtItem | FruitItem>

export const isShirt = (i: Item): i is ShirtItem => i.kind === Formats.Shirt
export const isFruit = (i: Item): i is FruitItem => i.kind === Formats.Fruit

export const getShirt = (i: Item): Shirt|null => isShirt(i) ? i.type : null
export const getFruit = (i: Item): Fruit|null => isFruit(i) ? i.type : null
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...