Search code examples
typescriptdesign-patternsvisitor-pattern

Visitor design pattern: can my visitor returns a Promise or should I create a new interface


I am now using a Visitor pattern where I have 2 visitors using the same interface returning T. It basically looks like the schema below, but my visitor returns something.

I would like to change the return type of one of my visitor to return a Promise.

Should I create a new interface for this issue?

enter image description here


Solution

  • If you want to make use of async/await, I think it makes sense to create a new interface called AsyncVisitor. Every visitor you implement should, in a sense, be thought of as its own "virtual" function on an enumeration of types. However, in JavaScript, Function and AsyncFunction are two inherently different types of functions, where the latter may suspend execution and must always return a Promise. Therefore, it doesn't make sense to have one visitor interface to represent both regular and async functions.

    While you could hypothetically implement your promise-based Visitor as just Visitor<Promise<T>> and async/await will still work, your interface would then mix and treat Function and AsyncFunction as interchangeable types, which can be unexpected if you're doing some kind of metaprogramming.

    In other words, I think your interfaces should look something like this:

    interface Visitor<T> {
      visitElementA(e: ElementA): T;
      visitElementB(e: ElementB): T;
    }
    
    interface AsyncVisitor<T> {
      visitElementAAsync(e: ElementA): Promise<T>;
      visitElementBAsync(e: ElementB): Promise<T>;
    }
    
    interface Element {
      accept<T>(v: Visitor<T>): T;
      acceptAsync<T>(v: AsyncVisitor<T>): Promise<T>;
    }