打字稿功能返回型继电器

时间:2019-05-28 19:18:32

标签: typescript

我有一个实现访问者模式的简单类:

abstract class MyNode {};
class MyNodeA extends MyNode {};
class MyNodeB extends MyNode {};

abstract class NodeVisitor {
  abstract visitMyNodeA(node: MyNodeA): unknown;
  abstract visitMyNodeB(node: MyNodeB): unknown;

  public visit(node: MyNode) {
    if(node instanceof MyNodeA) {
      return this.visitMyNodeA(node);
    } else if(node instanceof MyNodeB) {
      return this.visitMyNodeB(node);
    } else {
      throw new Error('Unknown node type on visitor');
    }
  } 
}

以及以后,我想在实现NodeVisitor

时在每个访问函数上都具有自定义返回类型
class MyNodeVisitor extends NodeVisitor {
  visitMyNodeA(node: MyNodeA): number {
    return 1;
  }
  visitMyNodeB(node: MyNodeB): number {
    return this.visit(new MyNodeA()) + 1;
  }
}

但这会产生错误,因为TypeScript编译器没有意识到对visit类型的参数MyNodeA的调用重定向到visitMyNodeA函数,该函数现在返回{{1 }}。

我将如何实施这样的解决方案?

1 个答案:

答案 0 :(得分:1)

是的,编译器无法自行解决。您可以通过增加复杂性(并降低visit()实现中的类型安全性)来帮助它。我的建议是给visit()一个generic签名,其返回类型是一个基于conditional typepolymorphic this type of subclasses

abstract class MyNode {myNode = "myNode"}
class MyNodeA extends MyNode {a = "a"}
class MyNodeB extends MyNode {b = "b"}

abstract class NodeVisitor {
  abstract visitMyNodeA(node: MyNodeA): unknown;
  abstract visitMyNodeB(node: MyNodeB): unknown;

  // call signature    
  public visit<T extends MyNode>(
    node: T
  ): T extends MyNodeA ? ReturnType<this["visitMyNodeA"]> : 
     T extends MyNodeB ? ReturnType<this["visitMyNodeB"]> : 
    never;

  // implementation signature is wider
  public visit(node: MyNode): unknown {
    if (node instanceof MyNodeA) {
      return this.visitMyNodeA(node);
    } else if (node instanceof MyNodeB) {
      return this.visitMyNodeB(node);
    } else {
      throw new Error("Unknown node type on visitor");
    }
  }
}    
class MyNodeVisitor extends NodeVisitor {
  visitMyNodeA(node: MyNodeA): number {
    return 1;
  }
  visitMyNodeB(node: MyNodeB): number {
    return this.visit(new MyNodeA()) + 1;
  }
}

行得通吗?这个想法是让您带领编译器进行以下分析:如果您传递MyNodeA,则visit()将返回this.visitMyNodeA(node)的结果,而对MyNodeB的返回结果也是相同的。

希望有所帮助;祝你好运!

Link to code