泛型函数的返回类型可以输入TypeScript中其参数的类型吗?

时间:2019-11-08 17:57:43

标签: typescript recursion tree return-type inference

假设我正在用TypeScript构建一个最小的编译器:

我有适用于不同类型文件的解析器:

interface Parser<ParsedTree extends object> {
  parse(buffer: Buffer): ParsedTree;
}

我有一些转换,可能会或可能不会突变已解析文件树的访问节点:

interface Transform<Node, TransformedNode> {
  pre(node: Node): TransformedNode;
  post(node: Node): TransformedNode;
}

我有目标,它们接受转换后的树,并对其进行处理(表面上将它们写入fs):

interface Target<TransformedTree> {
  write(tree: TransformedTree): void;
}

目标的TransformedTree类型应从转换返回的内容中得出。再说一次,我们得到每个变换的prepost的并集返回类型,并将其添加到已解析的树节点类型上。为此,我们获取了解析器的返回类型,然后使用以下实用程序类型将每个树类型的节点变成其自身的并集以及所有转换的prepost的返回类型方法:

export type ChildrenUnionWith<T, Append> = {
  [K in keyof T]: T[K] extends object
    ? ChildrenUnionWith<T[K], Append> | Append
    : T[K] | Append;
};

同时,通过使用以下实用程序获取所有Transform的节点的并集,我们得到了ParsedTree的第一个通用参数:

export type NodeOfTree<Tree> = Tree extends object
  ? ({[K in keyof Tree]: NodeOfTree<Tree[K]>}[keyof Tree] | Tree)
  : Tree;

我试图将这些类型拼凑成这样:

function compile<
  Parsers extends Parser<object>[],
  Transforms extends Transform<NodeOfTree<ParsedTree>, unknown>[],
  Targets extends Target<TransformedTree>[],
  ParsedTree = ReturnType<Parsers[number]["parse"]>,
  TransformedNode = ReturnType<Transforms[number]["pre" | "post"]>,
  TransformedTree = ChildrenUnionWith<ParsedTree, TransformedNode>
>(parsers: Parsers, transforms: Transforms, targets: Targets) {
  // do something
}

这可行...但是在运行时使用中,给定的Transform可能会作用于先前已转换的节点上。因此,我想将所有转换的返回类型通过管道传递回其第一个通用参数...我希望节点类型为–不仅是所有ParsedTree节点的并集,以及所有Transform prepost返回类型的并集。

以下内容无法按预期运行:

function compile<
  Parsers extends Parser<object>[],
  Transforms extends Transform<NodeOfTree<ParsedTree> | TransformedNode, unknown>[],
  Targets extends Target<TransformedTree>[],
  ParsedTree = ReturnType<Parsers[number]["parse"]>,
  TransformedNode = ReturnType<Transforms[number]["pre" | "post"]>,
  TransformedTree = ChildrenUnionWith<ParsedTree, TransformedNode>
>(parsers: Parsers, transforms: Transforms, targets: Targets) {
  // do something
}

当我通过以下参数时...

compile(
  [{parse: (_: Buffer) => ({a: "b", c: "d"})}],
  [
    {
      pre: (node) => {},
      post: (node) => {},
    },
  ],
  [{write: (node) => {}}],
);

...不仅没有类型错误,而且nodepre中的post类型是any:/

有人对我如何启用要查找的文字有任何建议吗?

谢谢!

0 个答案:

没有答案