Типы объединения как альтернатива перегрузки метода - PullRequest
0 голосов
/ 28 апреля 2018

Обзор

Я пытаюсь использовать TypeScript, чтобы написать эквивалент перегруженного метода в Java, и не могу сказать, если использование union types предоставляет какое-либо значение в этом конкретном случае, в отличие от использования отдельных имен функций. Эта же концепция актуальна в JavaScript (среди других языков), где переменная может иметь любой тип, а не два указанных типа.

Java с перегрузкой метода

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

void expectPickedApples(String treeName, int expectedAppleCount) {
   assert(pickApples(treeName) == expectedAppleCount);
}

void expectPickedApples(int treeIndex, int expectedAppleCount) {
   expectPickedApples(getTreeName(treeIndex), expectedAppleCount);
}

Параметры TypeScript

Теперь, допустим, мне нужны те же функциональные возможности в языке, где я не могу перегрузить метод, но я могу использовать типы объединения, такие как TypeScript. Опять же, это может относиться к JavaScript или другому языку, где тип переменной - любой.

Различные имена функций (вариант 1)

Я мог бы просто использовать разные имена функций, например ниже:

function expectPickedApplesForTreeName(treeName: string, expectedAppleCount: number) {
   expect(pickApples(treeName)).toBe(expectedAppleCount);
}

function expectPickedApplesForTreeIndex(treeIndex: number, expectedAppleCount: number) {
   getTreeName(treeIndex).then(treeName => {
      expectPickedApplesForTreeName(treeName, expectedAppleCount);
   });
}

Типы соединений (вариант 2)

Мое решение с использованием типов объединения будет выглядеть так:

function expectPickedApples(treeIdentifier: string | number, expectedAppleCount: number) {
   if (typeof(treeIdentifier) === 'number') {
      expect(pickApples(treeIdentifier)).toBe(expectedAppleCount);
   } else {
      getTreeName(treeIdentifier).then(treeName => {
         expect(pickApples(treeName)).toBe(expectedAppleCount);
      });
   }
}

Вопрос с рассуждением

Существуют случаи, когда использование типов объединений явно обеспечило бы ценность. Однако в этом случае я просто использую оператор if с типом, чтобы выбрать один из двух блоков. Какой вариант выше предпочтительнее? Есть ли лучшая альтернатива?

Вариант 1 обеспечивает компактные функции и тестируемость, а вариант 2 обеспечивает удобство и потенциальную читабельность.

Если бы я только вызывал эти функции и не обращал внимания на реализацию, я бы выбрал вариант 2, так как есть только одно имя функции, которое нужно запомнить, и код прост (всегда можно увидеть документацию по методу для запоминания значений параметров). ).

expectPickedApples('the old tree', 5);
expectPickedApples(3, 10);

вместо

expectPickedApplesForTreeName('the old tree', 5);
expectPickedApplesForTreeIndex(3, 10);

Однако, если бы мне принадлежала реализация этого кода, включая обязанности, такие как тестирование, вариант 1 кажется лучше. Например, было бы легче определить местоположение ошибки, например, если treeIndex нуждается в модификации перед тем, как получить имя или неудачно получить имя дерева (получение имени должно иметь свои собственные тесты, но, возможно, это вызов службы Я не могу доверять).

...