【问题标题】:How to get full AST representation of union type in typescript?如何在打字稿中获得联合类型的完整 AST 表示?
【发布时间】:2022-02-01 00:46:47
【问题描述】:

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

我已经尝试了几种现有的解决方案,包括this,但似乎大多数已经过时了。一些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 示例,但forEachDescendant 似乎在node 上不存在。

如何写一个函数来获取并集的元素数组?

预期功能:

import * as ts from "typescript";

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


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

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

【问题讨论】:

  • 不确定我是否理解这个问题。 exatrct 已经在 const sourceCode = "type Foo = 'one'|'two'"; 上工作以获取 ["one", "two"]。什么不起作用?
  • @TitianCernicova-Dragomir 但它不适用于type Foo = keyof Array&lt;number&gt;
  • 所以你想要联合的解析类型。
  • 是的,我想从type Foo = keyof Array&lt;number&gt; 获得["forEach", "reduce", "map" ...]。对不起,不够清楚。在我的问题中也做了更新

标签: typescript typescript-compiler-api


【解决方案1】:

您不能为此使用 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"

【讨论】:

    猜你喜欢
    • 2016-04-16
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 2017-05-18
    • 2021-08-05
    • 2020-11-30
    相关资源
    最近更新 更多