Skip to main content

Compilation Pipeline

The TypeScript compiler transforms TypeScript source code into JavaScript through a multi-stage pipeline. Each stage performs a specific role in the compilation process.

The Five Stages

The compilation process flows through five main components:
1

Scanner

Breaks source text into tokens (scanner.ts)The scanner reads the raw source text and converts it into a stream of tokens:
// From src/compiler/scanner.ts
export interface Scanner {
    getToken(): SyntaxKind;
    getTokenStart(): number;
    getTokenEnd(): number;
    getTokenText(): string;
    scan(): SyntaxKind;
}
2

Parser

Builds Abstract Syntax Tree (parser.ts)The parser consumes tokens from the scanner and constructs an AST:
// The parser creates nodes like:
interface SourceFile extends Node {
    statements: NodeArray<Statement>;
    endOfFileToken: Token<SyntaxKind.EndOfFileToken>;
}
3

Binder

Creates symbols and establishes scope (binder.ts)The binder walks the AST and creates symbols for declarations:
// From src/compiler/binder.ts
import { bindSourceFile } from "./binder.ts";

// Creates symbols and establishes:
// - Lexical environments
// - Control flow graphs
// - Symbol tables
4

Checker

Performs type checking and semantic analysis (checker.ts)The type checker is the heart of TypeScript:
// From src/compiler/checker.ts (line 1486)
export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
    // 3+ million bytes of type checking logic
    // Handles type inference, compatibility, etc.
}
5

Emitter

Generates JavaScript and declaration files (emitter.ts)The emitter produces the final output:
// From src/compiler/emitter.ts (line 752)
export function emitFiles(
    resolver: EmitResolver,
    host: EmitHost,
    targetSourceFile: SourceFile | undefined,
    { scriptTransformers, declarationTransformers }: EmitTransformers,
    emitOnly: boolean | EmitOnly | undefined
): EmitResult

Program Creation

The compilation process begins with creating a Program object:
// From src/compiler/program.ts (line 1499)
export function createProgram(
    rootNames: readonly string[],
    options: CompilerOptions,
    host?: CompilerHost,
    oldProgram?: Program,
    configFileParsingDiagnostics?: readonly Diagnostic[]
): Program

What a Program Does

Source File Management

  • Reads and parses all source files
  • Manages file dependencies
  • Handles module resolution

Type Checking

  • Creates the type checker
  • Performs semantic analysis
  • Reports diagnostics

Emit Coordination

  • Coordinates JavaScript output
  • Generates declaration files
  • Produces source maps

Incremental Builds

  • Reuses previous compilation state
  • Tracks file changes
  • Optimizes rebuild performance

Core Source Files

The compiler is organized into focused modules:
Lexical analysis and tokenization. Handles:
  • Character-by-character scanning
  • Token identification
  • JSX and template literal parsing
Syntax analysis and AST construction. Handles:
  • Grammar rules
  • Error recovery
  • JSDoc comment parsing
Symbol creation and scope establishment. Handles:
  • Symbol table construction
  • Control flow analysis
  • Container and scope management
Type checking and semantic analysis. Handles:
  • Type inference
  • Type compatibility
  • Signature resolution
  • Diagnostic generation
Code generation and output. Handles:
  • JavaScript emission
  • Declaration file generation
  • Source map creation
  • Transform application

Data Structures

Nodes

Every element in TypeScript is represented as a Node:
interface Node {
    kind: SyntaxKind;
    flags: NodeFlags;
    parent: Node;
    // Position information
    pos: number;
    end: number;
}

Symbols

Symbols represent named declarations:
interface Symbol {
    flags: SymbolFlags;
    name: string;
    declarations?: Declaration[];
    valueDeclaration?: Declaration;
}

Types

Types are the semantic representation of values:
interface Type {
    flags: TypeFlags;
    symbol?: Symbol;
    // Type-specific properties
}

Diagnostic Flow

Diagnostics (errors and warnings) can be generated at every stage of compilation.
Different types of diagnostics:
  • Syntactic: Parser errors (missing semicolons, invalid syntax)
  • Semantic: Type checker errors (type mismatches, undefined variables)
  • Declaration: Issues in .d.ts generation
  • Global: Configuration and file system errors

Performance Considerations

The compiler is optimized for incremental compilation:

Lazy Evaluation

Type checking is performed on-demand to avoid unnecessary work

Caching

Previous compilation results are reused when files haven’t changed

Parallel Processing

Independent files can be processed concurrently

Incremental Parsing

Parser reuses AST nodes from previous compilations

Next Steps

Type Checking

Deep dive into how TypeScript validates types

Module Resolution

Learn how imports are resolved

Emit

Understand JavaScript generation

Build docs developers (and LLMs) love