CodeBlanks Logo Icon CodeBlanks

AST traversal

Learn AST traversal with forEachChild.

What is forEachChild?

ts.forEachChild(node, visitFn) visits every direct child of an AST node in order and calls visitFn for each. Combined with a recursive visit function it is the standard way to walk the whole tree.

import ts from "typescript";

const sf = ts.createSourceFile(
  "app.ts", "const a = 1;", ts.ScriptTarget.Latest, true
);

function visit(node: ts.Node) {
  console.log(ts.SyntaxKind[node.kind]);
  ts.forEachChild(node, visit);
}
visit(sf);

SyntaxKind and type guards

Every node has a numeric .kind; ts.SyntaxKind[kind] gives its name. To test for specific node kinds you use type guards such as ts.isIdentifier, ts.isFunctionDeclaration and ts.isVariableStatement.

function visit(node: ts.Node) {
  if (ts.isIdentifier(node)) {
    console.log(node.text);
  }
  ts.forEachChild(node, visit);
}

Practice Count identifiers

Create a source file from function topla(a: number, b: number): number { return a + b; } with ts.createSourceFile. Write a recursive visit function; count Identifier nodes with ts.isIdentifier and descend with ts.forEachChild. Print the total count.

Starter code

index.ts
import * as ts from "typescript";

// Kaynak: function topla(a: number, b: number): number { return a + b; }
// SourceFile oluştur
// visit fonksiyonu yaz: Identifier düğümleri say
// forEachChild ile alt düğümlere in
// Toplam sayıyı yazdır

// kodunu buraya yaz

Sample solution

index.ts
import ts from "typescript";

const sourceText = "function topla(a: number, b: number): number { return a + b; }";
const sf = ts.createSourceFile("app.ts", sourceText, ts.ScriptTarget.Latest, true);

let count = 0;
function visit(node: ts.Node) {
  if (ts.isIdentifier(node)) {
    count++;
  }
  ts.forEachChild(node, visit);
}
visit(sf);
console.log(count);

Expected output

5

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What does ts.forEachChild(node, fn) do?

  • Mutates the node's text
  • Visits every child of a node in order Correct answer
  • Performs type checking
  • Creates a new AST node

Explanation: forEachChild passes each direct child of a node in order to the given function; it neither creates nodes nor mutates text.

2 Identifier text

Question
function visit(node: ts.Node) {
  if (ts.isIdentifier(node)) {
    console.log(node.____);
  }
  ts.forEachChild(node, visit);
}
Answer
function visit(node: ts.Node) {
  if (ts.isIdentifier(node)) {
    console.log(node.text);
  }
  ts.forEachChild(node, visit);
}

Explanation: Identifier.text gives the textual value of the identifier; the Identifier node has no name, value or key property.

3 AST visit parts

Term Meaning
ts.forEachChild Walks child nodes
node.kind Node kind number
ts.SyntaxKind[kind] Gives the kind name
ts.isIdentifier(node) Whether the node is an Identifier

All lessons in Expert