简体   繁体   English

打字稿功能返回型继电器

[英]Typescript function return type relay

I have a simple class that implements the visitor pattern: 我有一个实现访问者模式的简单类:

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');
    }
  } 
}

and later, I want to have custom return types on each visit function when I implement NodeVisitor 及以后,当我实现NodeVisitor时,我希望每个访问函数都具有自定义返回类型

class MyNodeVisitor extends NodeVisitor {
  visitMyNodeA(node: MyNodeA): number {
    return 1;
  }
  visitMyNodeB(node: MyNodeB): number {
    return this.visit(new MyNodeA()) + 1;
  }
}

but this generates an error because the TypeScript compiler does not realize that a call on visit with a parameter of type MyNodeA redirects to the visitMyNodeA function which now returns a number . 但这会产生错误,因为TypeScript编译器没有意识到使用MyNodeA类型的参数进行的visit MyNodeA重定向到visitMyNodeA函数,该函数现在返回一个number

How would I go about implementing such a solution? 我将如何实施这样的解决方案?

Yeah, the compiler can't figure that out by itself. 是的,编译器无法自行解决。 You can help it do so, at the expense of more complexity (and less type safety inside the visit() implementation). 您可以通过增加复杂性(以及visit()实现内部的类型安全性较低)为代价来做到这一点。 My suggestion is to give visit() a generic signature whose return type is a conditional type based on the polymorphic this type of subclasses : 我的建议是给visit()一个通用签名,其返回类型是基于this子类多态性条件类型

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;
  }
}

Does that work? 那样有用吗? The idea is that you are leading the compiler through the analysis that if you pass in a MyNodeA that visit() will return the result of this.visitMyNodeA(node) , and the same for MyNodeB . 这个想法是让您带领编译器进行以下分析:如果您传递MyNodeA ,则visit()将返回this.visitMyNodeA(node)的结果,对于this.visitMyNodeA(node)则返回相同的MyNodeB

Hope that helps; 希望能有所帮助; good luck! 祝好运!

Link to code 链接到代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM