Module 22: TypeScript Compiler API
The TypeScript Compiler API allows you to programmatically analyze, transform, and generate TypeScript code.
1. Setup
npm install typescript
npm install --save-dev @types/node
import * as ts from "typescript";
2. Creating Source Files
const sourceCode = `
function greet(name: string): string {
return "Hello, " + name;
}
`;
const sourceFile = ts.createSourceFile(
"temp.ts",
sourceCode,
ts.ScriptTarget.Latest,
true
);
3. Parsing and Visiting Nodes
function visit(node: ts.Node) {
console.log(ts.SyntaxKind[node.kind]);
if (ts.isFunctionDeclaration(node)) {
console.log("Function:", node.name?.text);
}
ts.forEachChild(node, visit);
}
visit(sourceFile);
4. Type Checking
function compile(fileNames: string[], options: ts.CompilerOptions) {
const program = ts.createProgram(fileNames, options);
const checker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
if (!sourceFile.isDeclarationFile) {
ts.forEachChild(sourceFile, visit);
}
}
function visit(node: ts.Node) {
if (ts.isFunctionDeclaration(node) && node.name) {
const symbol = checker.getSymbolAtLocation(node.name);
if (symbol) {
const type = checker.getTypeOfSymbolAtLocation(symbol, node);
console.log("Type:", checker.typeToString(type));
}
}
ts.forEachChild(node, visit);
}
}
5. Code Transformation
function transformer<T extends ts.Node>(context: ts.TransformationContext) {
return (rootNode: T) => {
function visit(node: ts.Node): ts.Node {
// Transform string literals to uppercase
if (ts.isStringLiteral(node)) {
return ts.factory.createStringLiteral(node.text.toUpperCase());
}
return ts.visitEachChild(node, visit, context);
}
return ts.visitNode(rootNode, visit);
};
}
const result = ts.transform(sourceFile, [transformer]);
const printer = ts.createPrinter();
const output = printer.printFile(result.transformed[0] as ts.SourceFile);
6. Finding References
const program = ts.createProgram(["file.ts"], {});
const sourceFile = program.getSourceFile("file.ts")!;
const checker = program.getTypeChecker();
function findReferences(node: ts.Node, name: string) {
if (ts.isIdentifier(node) && node.text === name) {
console.log("Found:", node.text, "at", node.pos);
}
ts.forEachChild(node, child => findReferences(child, name));
}
findReferences(sourceFile, "greet");
7. Generating Code
const statement = ts.factory.createVariableStatement(
undefined,
ts.factory.createVariableDeclarationList(
[ts.factory.createVariableDeclaration(
"message",
undefined,
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
ts.factory.createStringLiteral("Hello World")
)],
ts.NodeFlags.Const
)
);
const printer = ts.createPrinter();
const result = printer.printNode(ts.EmitHint.Unspecified, statement, sourceFile);
// Output: const message: string = "Hello World";
8. Real-World Use Cases
- Code generators (e.g., API client generators)
- Linters and formatters
- Documentation generators
- Code analysis tools
- AST transformations
Key Takeaways
✅ Compiler API enables programmatic TypeScript analysis
✅ Parse, transform, and generate code
✅ Type checking and symbol resolution
✅ Build custom tooling and code generators
Practice Exercises
Exercise 1: Find All Function Names
Write a visitor that collects all function names in a file.
Exercise 2: Add JSDoc Comments
Transform code to add JSDoc comments automatically.
Next Steps
In Module 23, we'll explore Testing with TypeScript, covering Jest, testing patterns, and type-safe tests.