Skip to main content
The TypeScript compiler represents source code as an Abstract Syntax Tree (AST) composed of nodes. All nodes implement the base Node interface and are classified by their SyntaxKind.

Base Node Interface

All AST nodes extend the Node interface:
interface Node extends ReadonlyTextRange {
  readonly kind: SyntaxKind;
  readonly flags: NodeFlags;
  readonly parent: Node;
}

Key Properties

PropertyTypeDescription
kindSyntaxKindThe syntax kind identifying the node type
flagsNodeFlagsBitwise flags for node properties
parentNodeParent node in the AST
posnumberStart position in source text
endnumberEnd position in source text

Core Node Types

Declaration Nodes

interface Declaration extends Node {
  _declarationBrand: any;
}

interface NamedDeclaration extends Declaration {
  readonly name?: DeclarationName;
}
Declaration nodes represent entities that introduce symbols into scope:
  • VariableDeclaration - Variable declarations
  • FunctionDeclaration - Function declarations
  • ClassDeclaration - Class declarations
  • InterfaceDeclaration - Interface declarations
  • TypeAliasDeclaration - Type alias declarations
  • EnumDeclaration - Enum declarations
  • ParameterDeclaration - Parameter declarations

Expression Nodes

Expressions are nodes that can be evaluated to produce a value:
type Expression = 
  | Identifier
  | BinaryExpression
  | CallExpression
  | PropertyAccessExpression
  | ArrayLiteralExpression
  | ObjectLiteralExpression
  // ... and many more
Common expression types:
TypeDescription
IdentifierVariable or property name
BinaryExpressionBinary operations (e.g., a + b)
CallExpressionFunction calls
PropertyAccessExpressionProperty access (e.g., obj.prop)
ElementAccessExpressionBracket notation (e.g., arr[0])
ArrowFunctionArrow function expressions
FunctionExpressionFunction expressions

Statement Nodes

Statements are executable units of code:
type Statement =
  | VariableStatement
  | ExpressionStatement
  | IfStatement
  | ForStatement
  | WhileStatement
  | ReturnStatement
  | ThrowStatement
  // ... and more

Type Nodes

Type nodes represent TypeScript type annotations:
type TypeNode =
  | TypeReference
  | FunctionType
  | UnionType
  | IntersectionType
  | ArrayType
  | TupleType
  // ... and more

Container Nodes

Some nodes act as containers for other declarations:
interface LocalsContainer extends Node {
  _localsContainerBrand: any;
}

interface FlowContainer extends Node {
  _flowContainerBrand: any;
}

LocalsContainer

Nodes that can contain local symbols:
  • SourceFile
  • FunctionDeclaration
  • ModuleDeclaration
  • Block
  • ForStatement
  • CatchClause

FlowContainer

Nodes with control flow analysis:
  • Functions and methods
  • Statements (if, while, for, etc.)
  • Expressions with side effects

Common Node Patterns

Signature Declarations

interface SignatureDeclarationBase extends NamedDeclaration {
  readonly kind: SignatureDeclaration["kind"];
  readonly name?: PropertyName;
  readonly typeParameters?: NodeArray<TypeParameterDeclaration>;
  readonly parameters: NodeArray<ParameterDeclaration>;
  readonly type?: TypeNode;
}
Used by:
  • FunctionDeclaration
  • MethodDeclaration
  • ConstructorDeclaration
  • CallSignatureDeclaration
  • ConstructSignatureDeclaration

Variable Declarations

interface VariableDeclaration extends NamedDeclaration {
  readonly kind: SyntaxKind.VariableDeclaration;
  readonly name: BindingName;
  readonly exclamationToken?: ExclamationToken;
  readonly type?: TypeNode;
  readonly initializer?: Expression;
}

Parameter Declarations

interface ParameterDeclaration extends NamedDeclaration {
  readonly kind: SyntaxKind.Parameter;
  readonly modifiers?: NodeArray<ModifierLike>;
  readonly dotDotDotToken?: DotDotDotToken;
  readonly name: BindingName;
  readonly questionToken?: QuestionToken;
  readonly type?: TypeNode;
  readonly initializer?: Expression;
}

Working with Nodes

Type Guards

Use type guards to narrow node types:
import ts from 'typescript';

if (ts.isVariableDeclaration(node)) {
  // node is VariableDeclaration
  console.log(node.name.getText());
}

if (ts.isFunctionDeclaration(node)) {
  // node is FunctionDeclaration
  console.log(node.name?.getText());
}

Traversing the AST

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

Node Relationships

Parent-Child

Every node (except the root) has a parent:
const parent = node.parent;
const children: ts.Node[] = [];
ts.forEachChild(node, child => children.push(child));

Source File

Get the source file for any node:
const sourceFile = node.getSourceFile();

See Also

Build docs developers (and LLMs) love