打字稿代码生成
#javascript #typescript #code #generation

您是否想知道如何自动生成打字稿代码?

使用Typescript编译器API,我们可以根据我们想要的任何规则来编写可以生成Typescript代码的脚本的函数!

要开始使用npm init创建一个新项目,然后使用npm install typescript安装“打字稿” NPM软件包。用touch index.mjs创建一个文件index.mjs,该文件将持有我们的代码生成脚本。

接下来,我们想弄清楚要生成哪种代码。对于此示例,我们将生成以下功能:

function add(a: number, b: number): number {
  return a + b;
}

这是一个非常简单的示例,但是这些概念适用于您要生成的任何类型的代码。

index.mjs中,导入“打字稿”软件包,然后开始通过Intellisense探索其中的内容。在此示例中,我们看到我们需要定义一些“标识符”,特别是abadd。这些都是“名称”,并由抽象语法树中的标识符表示。

我们可以使用称为createIdentifier
的工厂方法来定义文件顶部的每个标识符

const aId = ts.factory.createIdentifier("a");
const bId = ts.factory.createIdentifier("b");
const addId = ts.factory.createIdentifier("add");

我们还需要几次number关键字,因此我们可以在其他下方添加它:

const numberKeyword = ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)

然后,我们可以开始创建函数声明,并使用Intellisense弄清楚需要提供的内容:

const addFunc = ts.factory.createFunctionDeclaration(
  /* modifiers */,
  /* asteriskToken */,
  /* name */,
  /* typeParameters */,
  /* parameters */,
  /* type */,
  /* body */
)

我们可以看到,对于不同类型的AST节点,它需要几个插槽。我们需要使用其中的一些,而其他我们可以用undefined值留空。

前两个,modifiersasteriskToken,我们可以在这里留空,因为我们在这里不需要它们。下一个name我们可以使用我们之前定义的addId。对于typeParameters,我们可以留空。对于parameters,我们需要使用已经创建的标识符来定义每个参数的两个,每个参数。对于type,我们可以使用已经定义的numberKeyword,这表示函数的返回类型。最后,对于身体,我们将创建一个新的块节点,该节点包含一个带有二进制表达式的返回语句,将两个参数添加在一起。

这里有很多技术术语 - 有关此处提到的所有内容的深入详细信息,请查看我的新书“ The Typescript Compiler API”,其中解释了从A-Z for代码生成,AST等等!

然后将其打印出来,我们可以通过:
使用printer

function print(nodes) {
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
  const resultFile = ts.createSourceFile(
    "temp.ts",
    "",
    ts.ScriptTarget.Latest,
    false,
    ts.ScriptKind.TSX
  );

  console.log(printer.printList(ts.ListFormat.MultiLine, nodes, resultFile));
}

print([addFunc]);

最终脚本应该看起来像这样:

import ts from "typescript";

const aId = ts.factory.createIdentifier("a");
const bId = ts.factory.createIdentifier("b");
const addId = ts.factory.createIdentifier("add");
const numberKeyword = ts.factory.createKeywordTypeNode(
  ts.SyntaxKind.NumberKeyword
);

const addFunc = ts.factory.createFunctionDeclaration(
  undefined,
  undefined,
  addId,
  undefined,
  [
    ts.factory.createParameterDeclaration(
      undefined,
      undefined,
      aId,
      undefined,
      numberKeyword,
      undefined
    ),
    ts.factory.createParameterDeclaration(
      undefined,
      undefined,
      bId,
      undefined,
      numberKeyword,
      undefined
    ),
  ],
  numberKeyword,
  ts.factory.createBlock(
    [
      ts.factory.createReturnStatement(
        ts.factory.createBinaryExpression(
          aId,
          ts.factory.createToken(ts.SyntaxKind.PlusToken),
          bId
        )
      ),
    ],
    true
  )
);

function print(nodes) {
  const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
  const resultFile = ts.createSourceFile(
    "temp.ts",
    "",
    ts.ScriptTarget.Latest,
    false,
    ts.ScriptKind.TSX
  );

  console.log(printer.printList(ts.ListFormat.MultiLine, nodes, resultFile));
}

print([addFunc]);

运行node index.mjs时,我们应该看到以下打印到控制台:

function add(a: number, b: number): number {
    return a + b;
}

恭喜,您刚刚生成了第一个功能!如果您喜欢此练习,并想了解有关代码生成,抽象语法树,衬里,客户诊断等方面的更多信息,则可以随意查看我的new book,该new book涵盖了所有这些深入介绍。欢呼!