Обзор
Я пытаюсь использовать 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 нуждается в модификации перед тем, как получить имя или неудачно получить имя дерева (получение имени должно иметь свои собственные тесты, но, возможно, это вызов службы Я не могу доверять).