BehavioralTypeScriptverifiedVerified

Visitor Pattern in TypeScript

Lets you add new operations to an object structure without modifying the objects themselves, by separating the algorithm from the object structure it operates on.

How to Implement the Visitor Pattern in TypeScript

1Step 1: Define the Visitor and Element interfaces

interface ShapeVisitor {
  visitCircle(shape: Circle): number;
  visitRectangle(shape: Rectangle): number;
  visitTriangle(shape: Triangle): number;
}

interface Shape {
  accept<T>(visitor: { visitCircle(s: Circle): T; visitRectangle(s: Rectangle): T; visitTriangle(s: Triangle): T }): T;
}

2Step 2: Implement concrete elements with accept methods

class Circle implements Shape {
  constructor(public radius: number) {}
  accept<T>(visitor: { visitCircle(s: Circle): T; visitRectangle(s: Rectangle): T; visitTriangle(s: Triangle): T }): T {
    return visitor.visitCircle(this);
  }
}

class Rectangle implements Shape {
  constructor(public width: number, public height: number) {}
  accept<T>(visitor: { visitCircle(s: Circle): T; visitRectangle(s: Rectangle): T; visitTriangle(s: Triangle): T }): T {
    return visitor.visitRectangle(this);
  }
}

class Triangle implements Shape {
  constructor(public base: number, public height: number, public sideA: number, public sideB: number) {}
  accept<T>(visitor: { visitCircle(s: Circle): T; visitRectangle(s: Rectangle): T; visitTriangle(s: Triangle): T }): T {
    return visitor.visitTriangle(this);
  }
}

3Step 3: Create visitors for area and perimeter calculations

const areaVisitor: ShapeVisitor = {
  visitCircle:    s => Math.PI * s.radius ** 2,
  visitRectangle: s => s.width * s.height,
  visitTriangle:  s => 0.5 * s.base * s.height,
};

const perimeterVisitor: ShapeVisitor = {
  visitCircle:    s => 2 * Math.PI * s.radius,
  visitRectangle: s => 2 * (s.width + s.height),
  visitTriangle:  s => s.base + s.sideA + s.sideB,
};

4Step 4: Apply visitors to a collection of shapes

const shapes: Shape[] = [new Circle(5), new Rectangle(4, 6), new Triangle(3, 4, 3, 5)];

console.log("Areas:",     shapes.map(s => s.accept(areaVisitor)));
console.log("Perimeters:", shapes.map(s => s.accept(perimeterVisitor)));

Visitor Pattern Architecture

hourglass_empty

Rendering diagram...

lightbulb

Visitor Pattern in the Real World

Think of a tax auditor visiting different types of businesses—a restaurant, a law firm, a retail shop. The auditor (visitor) knows exactly what to examine at each type of business and applies the appropriate inspection procedure. The businesses (elements) simply let the auditor in; they don't change their own operations to accommodate the audit.