public interface Calculation {
int doCalc(int x, int y);
}
@Getter
@AllArgsConstructor
public enum Calculator {
PLUS(Integer::sum),
MINUS((x, y) -> x - y),
MULTIPLY((x, y) -> x * y),
DIVIDE((x, y) -> x / y);
private Calculation calculation;
}
위 코드 처럼 함수형 인터페이스를 이용하여 Enum값에 따라 동적인 처리가 가능하다.
테스트 해보자
class CalculatorTest {
@Test
void calc() {
assertThat(Calculator.PLUS.getCalculation().doCalc(5, 5)).isEqualTo(10);
assertThat(Calculator.MINUS.getCalculation().doCalc(5, 5)).isEqualTo(0);
assertThat(Calculator.MULTIPLY.getCalculation().doCalc(5, 5)).isEqualTo(25);
assertThat(Calculator.DIVIDE.getCalculation().doCalc(5, 5)).isEqualTo(1);
}
}

타입스크립트는 Enum타입을 열거형으로만 사용할 수 있다. (상수용)
자바의 Enum처럼 특정 연산을 수행할 수 없다.
그래서 static 배열을 활용해 나름대로 구현해 보았다.
export class Calculator {
static readonly operators: Calculation[] = [
{operator: 'plus', do: (x, y) => x + y},
{operator: 'minus', do: (x, y) => x - y},
{operator: 'multiply', do: (x, y) => x * y},
{operator: 'divide', do: (x, y) => x / y},
]
static find(operator: string) {
return this.operators.filter(o => o.operator === operator).pop();
}
}
export interface Calculation {
operator: string;
do: (x: number, y: number) => number;
}
배열과 인터페이스를 이용하여 구현해보았다.
연산자값을 받아서 해당 값에 맞는 연산을 수행한다.
테스트 해보자
describe('enumTest', () => {
it('calculator', async () => {
expect(Calculator.find('plus').do(5, 5)).toBe(10);
expect(Calculator.find('minus').do(5, 5)).toBe(0);
expect(Calculator.find('multiply').do(5, 5)).toBe(25);
expect(Calculator.find('divide').do(5, 5)).toBe(1);
});

잘 작동한다.
배열을 이용한 방식은 switch문이나 if문 없이 동적인 처리가 가능하지만, enum의 장점을 제대로 누리진 못한다. (IDE 지원, 컴파일 시점 체크 등)
ts-jenum이란 라이브러리가 있다.
타입스크립트에서 Enum을 보다 다이나믹하게 사용할 수 있게 해준다. 마치 자바의 Enum 처럼.
npm install ts-jenum
@Enum('operator')
export class ECalculator extends EnumType<ECalculator>() {
static readonly PLUS = new ECalculator('PLUS', (x, y) => x + y);
static readonly MINUS = new ECalculator('MINUS', (x, y) => x - y);
static readonly MULTIPLY = new ECalculator('MULTIPLY', (x, y) => x * y);
static readonly DIVIDE = new ECalculator('DIVIDE', (x, y) => x / y);
private constructor(readonly operator: string, readonly calculation: (x: number, y: number) => number) {
super();
}
calc(operator: string, x: number, y: number) {
return ECalculator.values().filter(e => e.operator === operator).pop().calculation(x, y);
}
}
EnumType을 상속 받는다.
@Enum('key')는 괄호안에 값이 해당 Enum값의 키 값이 된다.
위 코드에서는 연산자를 key값으로 지정하고, 람다로 계산을 하는 함수를 구현했다.
테스트 해보자.
describe('enumTest', () => {
it('Ecalculation', async () => {
expect(ECalculator.PLUS.calculation(5, 5)).toBe(10);
expect(ECalculator.MINUS.calculation(5, 5)).toBe(0);
expect(ECalculator.MULTIPLY.calculation(5, 5)).toBe(25);
expect(ECalculator.DIVIDE.calculation(5, 5)).toBe(1);
});
it('Ecalc', async () => {
expect(ECalculator.PLUS.calc('PLUS', 5, 5)).toBe(10);
expect(ECalculator.MINUS.calc('MINUS', 5, 5)).toBe(0);
expect(ECalculator.MULTIPLY.calc('MULTIPLY', 5, 5)).toBe(25);
expect(ECalculator.DIVIDE.calc('DIVIDE', 5, 5)).toBe(1);
});
});
Enum값의 calculation을 호출하여 계산하는 테스트와, Enum값의 key(연산자)값을 받아서 해당 Enum값을 찾은 후 계산을 수행하는 calc라는 함수를 사용하는 테스트 총 두가지 테스트를 해보았다.

잘 작동한다.
Enum을 적극적으로 사용하고 싶다면 ts-jenum을 사용해보자.