Можно ли передать тип возвращаемой функции универсальной функции в типы ее аргументов в TypeScript? - PullRequest
1 голос
/ 08 ноября 2019

Допустим, я создаю минимальный компилятор в TypeScript:

У меня есть парсеры, которые применяются к различным типам файлов:

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

У меня есть преобразования, которые могут изменяться или не изменятьсяпосещенные узлы деревьев проанализированных файлов:

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

И у меня есть цели, которые принимают преобразованные деревья и что-то с ними делают (якобы записывают их в фс):

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

Тип цели TransformedTree должен быть взят из того, что возвращают преобразования. Ака., Мы получаем возвращаемый тип объединения для всех преобразований 'pre и post и добавляем его в анализируемые типы узлов дерева. Для этого мы получаем возвращаемые типы синтаксического анализатора, а затем используем следующий тип утилиты, чтобы превратить каждый из узлов типа дерева в объединение самого себя, а затем возвращаем типы всех преобразований: методы pre и post:

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 pre и post.

Следующее не работает должным образом:

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) => {}}],
);

... не только нет ошибок типа, но node тип pre и post равен any: /

У кого-нибудь есть какие-либо предложенияо том, как я мог бы разрешить ввод, который я ищу?

Спасибо!

...