EN 10 feb 2026

Expression Trees: What They Are and How to Solve Them with JavaScript/TypeScript

By Mariana Garcia Berrueta

This post explains what an expression tree is and how it is used to represent and evaluate mathematical operations. You’ll learn how its structure works, why recursion is key to evaluating it, and how to implement it step by step with JavaScript/TypeScript.

What Is an Expression Tree?

An expression tree is a binary data structure used to represent and evaluate mathematical and logical operations.

An expression tree has two main characteristics:

1.- It is a binary tree

It is a structure composed of nodes (elements or pieces of data). Unlike a linear structure, a tree is organized hierarchically, which means each node is positioned above or below another.

From each node, up to two child nodes can branch out.

If you want to learn more about binary trees, visit the post “Binary Tree: What It Is, Uses, Types, and How to Create One with JavaScript/TypeScript.”

2.- It evaluates mathematical and logical operations

Expression trees are mainly used in:

They allow operations such as addition, subtraction, multiplication, and division to be represented in a structured way.

How Is an Expression Tree Formed?

A tree is made up of two main types of nodes:

  1. Leaf nodes: These are the nodes found at the ends of the tree. They have no children and usually represent numeric values.
  2. Internal nodes: These nodes have at least one child. In an expression tree, they represent mathematical operators such as +, -, *, or /.

How Do You Evaluate an Expression Tree?

Expression trees are evaluated from the bottom up. This happens because the tree structure respects operator precedence:

Simple example:

Let’s solve the expression: (2 + 1) * 3

First, we solve the deepest operation:

2 + 1 = 3

This result becomes a node that is then multiplied by 3.

Finally:

3 * 3 = 9

This is how an expression tree allows us to evaluate operations in the correct order.

👉 In summary: An expression tree is solved from the bottom up, evaluating the most internal operations first until reaching the final result.

How to Create an Expression Tree with Code?

To create an expression tree, we can use a class that represents a tree node.

class BinaryTree {
    value: number | "add" | "subtract" | "multiply"
    left: BinaryTree | null
    right: BinaryTree | null
    
    constructor(value: number | "add" | "subtract" | "multiply") {
        this.value = value
        this.left = null
        this.right = null
    }
}

This class contains three properties:

To better understand how to create a binary tree from scratch, you can visit the article mentioned earlier.

How Do We Solve an Expression Tree Recursively?

First, let’s understand what a recursive function is and why recursion is natural for trees.

A recursive function is one that calls itself until it reaches a base case that stops execution.

For example, imagine we want to count from 3 down to 0 and print each number to the console. Our base case is reaching 0; once that happens, the function stops. The function receives a number and subtracts 1 on each call. With recursion, the function keeps calling itself until it reaches that base case.

const count = (number: number): void => {
    if (number === 0) return; // base case (stops the function)
    console.log(number)
    count(number - 1); // the function calls itself
};

count(3);

Recursion is especially useful when working with trees because each node in a tree can be seen as a smaller tree.

Think of a real tree 🌳. If you look at a large branch, you’ll notice it resembles the entire tree—it also has smaller branches that continue dividing.

The same happens in a data tree. Each node has:

Solving the entire tree is simply repeating the same process on each of its subtrees.

Now we are ready to solve our expression tree.

Step 1 — Create the Function with TypeScript

The function receives a node and must return a number.

const evaluateExpressionTree = (node: BinaryTree | null): number => {}

Step 2 — Define the Base Cases

We want to stop recursion when:

The node is null. Here we return 0 for simplicity, but using throw new Error may be a better practice.

The node contains a number (it is a leaf node). In that case, we return the value so it can be used in the mathematical operation.

const evaluateExpressionTree = (node: BinaryTree | null): number => {
    if (!node) return 0
    
    if (typeof node.value === "number") {
        return node.value
    }
}

Step 3 — Evaluate the Subtrees

Now we evaluate the children:

const leftValue = evaluateExpressionTree(node.left)
const rightValue = evaluateExpressionTree(node.right)

The leftValue and rightValue are the result of recursively calling evaluateExpressionTree.

Step 4 — Apply the Operation

We use a switch statement that adds, subtracts, or multiplies depending on the node’s value.

const evaluateExpressionTree = (node: BinaryTree | null): number => {
    if (!node) return 0
    
    if (typeof node.value === "number") {
        return node.value
    }
    
    const leftValue = evaluateExpressionTree(node.left)
    const rightValue = evaluateExpressionTree(node.right)
    
    switch (node.value) {
      case "add":
          return leftValue + rightValue
      case "subtract":
          return leftValue - rightValue
      case "multiply":
          return leftValue * rightValue
    }
    
    return 0
}

Now we have a function capable of evaluating an entire tree.

I recommend grabbing a piece of paper and a pencil and trying to solve a simple tree by following the function step by step.

Related Posts