interface Expression { evaluate(): number } type UnaryOperator = "+" | "-" type BinaryOperator = "+" | "-" | "*" | "/" | "^" class Value implements Expression { readonly value: number constructor(value: number) { this.value = value } evaluate(): number { return this.value } } class UnaryExpression implements Expression { readonly operator: UnaryOperator readonly operand: Expression constructor(operator: UnaryOperator, operand: Expression) { this.operator = operator this.operand = operand } evaluate(): number { const value = this.operand.evaluate() if (this.operator === "-") return (-1 * value) else return value } } class BinaryExpression implements Expression { readonly operator: BinaryOperator readonly left: Expression readonly right: Expression constructor(operator: BinaryOperator, left: Expression, right: Expression) { this.operator = operator this.left = left this.right = right } evaluate(): number { const leftV = this.left.evaluate() const rightV = this.right.evaluate() if (this.operator === "+") return (leftV + rightV) else if (this.operator === "-") return (leftV - rightV) else if (this.operator === "*") return (leftV * rightV) else if (this.operator === "^") return (leftV ** rightV) else { if (rightV === 0) throw new Error("Division by zero error") else return (leftV / rightV) } } } const e1 = new UnaryExpression("+", new Value(10)) const e2 = new UnaryExpression("-", new Value(20.1)) console.log(e1.evaluate() === 10) console.log(e2.evaluate() === -20.1) const e3 = new BinaryExpression("+", new Value(2), new Value(3)) const e4 = new BinaryExpression("-", new Value(2), new Value(3)) const e5 = new BinaryExpression("*", new Value(2), new Value(3)) const e6 = new BinaryExpression("/", new Value(2), new Value(3)) const e7 = new BinaryExpression("^", new Value(2), new Value(8)) const e8 = new BinaryExpression("/", new Value(2), new Value(0)) console.log(e3.evaluate()) console.log(e4.evaluate()) console.log(e5.evaluate()) console.log(e6.evaluate()) console.log(e7.evaluate()) console.log(e8.evaluate())