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现在返回number.

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

杰卡兹

是的,编译器自己无法解决这个问题。您可以帮助它做到这一点,但代价是更加复杂(以及visit()实现内部的类型安全性较低)。我的建议是给出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;
  }
}

那样有用吗?我们的想法是,你是通过分析主要的编译器,如果你在一传MyNodeAvisit()将返回的结果this.visitMyNodeA(node),与同为MyNodeB

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

代码链接

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章