Skip to main content

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.