0Pricing
TypeScript Academy · 课时

自定义转换器与代码生成

编写可修改 AST 的编译器转换器

自定义转换器与代码生成 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。

什么是转换器

TypeScript 转换器是接收 AST 节点并返回一个(可能经过修改的)节点的函数。它们在编译期间运行,以生成自定义输出。

import ts from "typescript";
type Transformer = ts.TransformerFactory<ts.SourceFile>;

转换器工厂的形态

转换器工厂接收一个 TransformationContext,并返回一个用于转换 SourceFile 节点的函数。

const myTransformer: ts.TransformerFactory<ts.SourceFile> =
  (ctx) => (sf) => {
    function visit(node: ts.Node): ts.Node {
      // Modify node here
      return ts.visitEachChild(node, visit, ctx);
    }
    return ts.visitNode(sf, visit) as ts.SourceFile;
  };

使用上下文进行访问

ts.visitEachChild(而不是 forEachChild)在转换器内部使用,因为它会正确地重建经过修改的节点。

function visit(node: ts.Node): ts.Node {
  if (ts.isStringLiteral(node)) {
    return ts.factory.createStringLiteral(node.text.toUpperCase());
  }
  return ts.visitEachChild(node, visit, ctx);
}

使用 ts.factory 创建新节点

ts.factory 对象提供了创建每种 AST 节点的方法。

const newCall = ts.factory.createCallExpression(
  ts.factory.createIdentifier("console.log"),
  undefined,
  [ts.factory.createStringLiteral("hello")]
);

将转换器应用于程序

将转换器传递给 program.emit 的 customTransformers 选项。

program.emit(undefined, undefined, undefined, false, {
  before: [myTransformer],
});

代码生成:打印节点

使用 ts.createPrinter 将 AST 节点转换回源代码字符串,而无需运行完整编译器。

const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
const result = printer.printNode(
  ts.EmitHint.Unspecified,
  newCall,
  sf
);
console.log(result); // console.log("hello")

生成完整的源文件

您可以使用 ts.factory.createSourceFile 从头创建完整的源文件,也可以通过组装语句节点列表来创建。

const statements = [
  ts.factory.createExpressionStatement(
    ts.factory.createCallExpression(
      ts.factory.createIdentifier("console.log"),
      undefined,
      [ts.factory.createStringLiteral("generated!")]
    )
  ),
];

转换导入

常见用例是转换导入路径——例如,在输出时将别名路径重写为相对路径。

if (ts.isImportDeclaration(node)) {
  const spec = node.moduleSpecifier as ts.StringLiteral;
  if (spec.text.startsWith("@app/")) {
    return ts.factory.updateImportDeclaration(
      node, node.modifiers, node.importClause,
      ts.factory.createStringLiteral(spec.text.replace("@app/", "../")),
      node.assertClause
    );
  }
}

测试转换器

通过将转换器应用于一个小型源文件,并断言打印出的输出与预期字符串一致,来测试转换器。

const result = ts.transpileModule("const x = 'hello';", {
  compilerOptions: { target: ts.ScriptTarget.ES2020 },
  transformers: { before: [myTransformer] },
});
console.log(result.outputText);

插件系统

某些构建工具(例如 ttypescript / ts-patch)允许您在 TypeScript 配置文件中将转换器注册为插件,从而让它们对开发工作流透明。

// tsconfig.json with ts-patch:
// "plugins": [{ "transform": "./my-transformer.js" }]

回顾:自定义转换器

转换器可以在编译期间于 AST 层面重写 TypeScript 代码。使用 ts.visitEachChild 进行递归遍历,使用 ts.factory 创建节点,并使用 ts.createPrinter 生成源代码文本。

快速检查

在转换器中,使用哪个对象创建新的 AST 节点?

您学到的内容

自定义转换器会在编译时修改 TypeScript AST。使用 ts.visitEachChild 进行递归,使用 ts.factory 构建新节点,并通过带有 customTransformers 的 program.emit 应用转换器。

常见问题解答

「自定义转换器与代码生成」课时是免费的吗?

是的 — 「自定义转换器与代码生成」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。

「自定义转换器与代码生成」这节课中我会学到什么?

编写可修改 AST 的编译器转换器 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 TypeScript Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「自定义转换器与代码生成」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 TypeScript Academy 课中编写并运行代码吗?

能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 API 创建 TypeScript 程序
  2. 使用访问器遍历 AST
  3. 自定义转换器与代码生成
  4. 构建简单的代码检查工具
← 返回 TypeScript Academy