Custom transformer
- TypeScript course
- Expert
- Lesson 7/35
- 4 min
Learn to write your own transformer.
Writing a custom transformer
When writing your own transformer you define a visitor function. The visitor recognizes specific nodes and replaces them with new nodes built via ts.factory. For other nodes you descend with ts.visitEachChild.
function visit(node: ts.Node): ts.Node {
if (ts.isStringLiteral(node)) {
return ts.factory.createStringLiteral("X");
}
return ts.visitEachChild(node, visit, context);
}When the visitor returns a new node, that branch is replaced entirely.
Node replacement and visitEachChild
There are two ways to change a node: return a completely new node, or update the existing node's fields with ts.factory.updateX. visitEachChild automatically updates the parent when a child changes.
// visitEachChild is recommended even for identity
return ts.visitEachChild(node, visit, context);Practice Replace strings with "X"
Create a source with const a = 'merhaba'; and const b = 'dünya';. Write a transformer that replaces every StringLiteral node found with ts.isStringLiteral by ts.factory.createStringLiteral("X"). Apply it with ts.transform and print the result with the Printer.
Starter code
import * as ts from "typescript";
// Kaynak: const a = 'merhaba'; const b = 'dünya';
// SourceFile oluştur
// Bir transformer yaz: StringLiteral düğümlerini "X" ile değiştir
// transform ile uygula
// Printer ile sonucu yazdır
// kodunu buraya yazSample solution
import ts from "typescript";
const sourceText = `const a = 'merhaba';\nconst b = 'dünya';`;
const sf = ts.createSourceFile("app.ts", sourceText, ts.ScriptTarget.Latest, true);
const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
function visit(node: ts.Node): ts.Node {
if (ts.isStringLiteral(node)) {
return ts.factory.createStringLiteral("X");
}
return ts.visitEachChild(node, visit, context);
}
return (node) => ts.visitEachChild(node, visit, context);
};
const result = ts.transform(sf, [transformer]);
const printer = ts.createPrinter();
process.stdout.write(printer.printFile(result.transformed[0] as ts.SourceFile));
result.dispose();Expected output
const a = "X"; const b = "X";
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 To change a node in a custom transformer, what do you do?
- You call program.getTypeChecker
- You mutate the node's text property directly
- You return a new node in the visitor function Correct answer
- You print the node with console.log
Explanation: AST nodes are immutable; you cannot mutate the text property. When the visitor returns a new node, that branch is replaced.
2 Replace a string literal
function visit(node: ts.Node): ts.Node {
if (ts.isStringLiteral(node)) {
return ts.factory.____("X");
}
return ts.visitEachChild(node, visit, context);
}
function visit(node: ts.Node): ts.Node {
if (ts.isStringLiteral(node)) {
return ts.factory.createStringLiteral("X");
}
return ts.visitEachChild(node, visit, context);
}
Explanation: createStringLiteral produces a new StringLiteral node; createString does not exist on the factory and updateStringLiteral updates an existing node (we want a new one here).
3 Custom transformer parts
| Term | Meaning |
|---|---|
Visitor fonksiyonu |
Recognizes and returns nodes |
ts.factory.createStringLiteral |
Produces a new string node |
ts.visitEachChild |
Transforms child nodes |
ts.isStringLiteral |
Tests the node kind |