自定义转换器与代码生成
编写可修改 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 反馈 — 无需本地设置。