如何在打字稿中获得联合类型的完整 AST 表示?

How to get full AST representation of union type in typescript?

我知道 ts-ast-viewer,但我不知道他们如何从联合中提取元素列表。

我已经尝试了几种现有的解决方案,包括 ,但似乎大多数都已过时。一些 ts.[methods] 现在已弃用。

这是启动调试编译器的初始代码API:

import * as ts from "typescript";

const code = "type Foo = 'one'|'two'|'three'";
const sourceFile = ts.createSourceFile(
  "foo.ts",
  code,
  ts.ScriptTarget.Latest,
  true
);

function print(node: ts.Node, name: string) {
  console.log({ node });
}

print(sourceFile, "Foo");

我知道 TS wiki 中的示例。这是我稍微修改过的版本:

//@ts-ignore
import * as ts from "typescript";

const code = "type Foo = 'one'|'two'|'three'";
const sourceFile = ts.createSourceFile(
  "foo.ts",
  code,
  ts.ScriptTarget.Latest,
  true
);

function extract(identifiers: string[]): void {
  //@ts-ignore
  const unfoundNodes = [];
  //@ts-ignore
  const foundNodes = [];
  //@ts-ignore

  ts.forEachChild(sourceFile, (node) => {
    let name = "";
    //@ts-ignore
    if (ts.isFunctionDeclaration(node)) {
      //@ts-ignore
      name = node.name.text;
      //@ts-ignore
      node.body = undefined;
      //@ts-ignore
    } else if (ts.isVariableStatement(node)) {
      //@ts-ignore
      name = node.declarationList.declarations[0].name.getText(sourceFile);
      //@ts-ignore
    } else if (ts.isInterfaceDeclaration(node)) {
      name = node.name.text;
    }
    //@ts-ignore
    const container = identifiers.includes(name) ? foundNodes : unfoundNodes;
    //@ts-ignore
    container.push([name, node]);
  });
  //@ts-ignore
  return (unfoundNodes[0][1] as any).type.types.map(
    (elem: any) => elem.literal.text
  );
}

// Run the extract function with the script's arguments
console.log(extract(["Foo"]));

并且有效。但是,如果我将源代码从 "type Foo = 'one'|'two'|'three'" 更改为 "type Foo = keyof Array<any>" - 它不会。

我知道我的版本不对

此外,我试过 this 示例,但似乎 forEachDescendantnode 上不存在。

如何写一个函数来获取联合数组的元素?

预期函数:

import * as ts from "typescript";

const sourceCode = "type Foo = keyof Array<number>";


union(sourceCode, "Foo") // ["forEach", "reduce", "map" ...]

我需要这个用于调试目的。

您不能为此使用 AST,因为 AST 仅包含有关文本在文件中的外观的信息,而不包含代码的某些部分与其他部分的关系。为此,您需要使用类型检查器。这是一个独立的例子:

// available as @ts-morph/bootstrap on npm
import { ts, createProjectSync } from "https://deno.land/x/ts_morph@13.0.3/bootstrap/mod.ts";

// setup code... you can use the vanilla ts compiler for this, but it's a lot of work
const project = createProjectSync();
const sourceCode = "type Foo = keyof Array<number>";
const sourceFile = project.createSourceFile("file.ts", sourceCode);
const typeChecker = project.createProgram().getTypeChecker();

// example use with the compiler API
const fooTypeAlias = sourceFile.statements[0] as ts.TypeAliasDeclaration;

const fooType = typeChecker.getTypeAtLocation(fooTypeAlias.name);
if (fooType.isUnion()) {
  for (const type of fooType.types) {
    console.log(typeChecker.typeToString(type, fooTypeAlias.name));
  }
}

输出:

number
"length"
"toString"
"toLocaleString"
"pop"
"push"
"concat"
"join"
"reverse"
"shift"
"slice"
"sort"
"splice"
"unshift"
"indexOf"
"lastIndexOf"
"every"
"some"
"forEach"
"map"
"filter"
"reduce"
"reduceRight"