What It Is
The Interpreter pattern evaluates sentences in a small language by building a tree of expression nodes — numbers, additions, subtractions — and then walking that tree. A number evaluates to itself; an addition evaluates its two sides and adds them.
In TypeScript the tree is a discriminated union: every node is a plain object with a kind field, and one function switches on that field. Because the union lists every node type, the compiler complains if a case is missing.
It fits small languages: filters, formulas, simple rules. Real languages deserve real parser tools.
Example: A Tiny Calculator
The input 3 + 4 - 2 becomes a tree of number, add and subtract nodes. One call to interpret() on the root evaluates the whole expression.
One tree, one interpret function
parse builds the tree left to right; interpret walks it and prints 3 + 4 - 2 = 5. Supporting * would be one new member of the union plus one new case — the existing ones stay untouched.
Output: TypeScript file and captured output
// Every node is a plain object tagged with a kind.
type Expression =
| { kind: "number"; value: number }
| { kind: "add"; left: Expression; right: Expression }
| { kind: "subtract"; left: Expression; right: Expression }
function interpret(expr: Expression): number {
switch (expr.kind) {
case "number":
return expr.value
case "add":
return interpret(expr.left) + interpret(expr.right)
case "subtract":
return interpret(expr.left) - interpret(expr.right)
}
}
function parse(input: string): Expression {
const parts = input.split(" ")
let expr: Expression = { kind: "number", value: Number(parts[0]) }
for (let i = 1; i < parts.length; i += 2) {
const right: Expression = { kind: "number", value: Number(parts[i + 1]) }
expr = parts[i] === "+"
? { kind: "add", left: expr, right }
: { kind: "subtract", left: expr, right }
}
return expr
}
const input = "3 + 4 - 2"
console.log(input, "=", interpret(parse(input)))
When to Use It
Use it when users or configs express logic in a small language of your design: search filters, pricing formulas, validation rules.
Skip it when the “language” is three fixed options (a plain switch is enough) — or a real language (use a parser generator or an existing engine).
Pros and Cons
Pros: the grammar maps one-to-one onto the members of the union; new operations are new members; expression trees can be built, checked and reused.
Cons: grows painful as the grammar grows; parsing itself still has to be written; performance is modest compared to compiled logic.