This page documents the transformer architecture that converts a type-checked TypeScript AST into an output-ready JavaScript AST. The transformation pipeline runs after type checking (see page Type Checker) and before the emitter prints text output (see page Emitter).
The pipeline handles two categories of work:
The entry point is transformNodes in src/compiler/transformer.ts248-357 It creates a TransformationContext, initializes each transformer by calling its factory, then passes each source file through every transformer in sequence.
Diagram: Transformer Orchestration
Sources: src/compiler/transformer.ts248-357 src/compiler/transformer.ts120-197
TransformerFactory and TransformerEvery built-in and custom transformer follows this shape:
A factory is called once per transformation pass to receive the TransformationContext. It returns a Transformer function that is called on each root node (typically SourceFile or Bundle).
Sources: src/compiler/transformer.ts56-57
TransformationContextTransformationContext is the shared interface provided to every transformer. It is constructed once inside transformNodes and passed to all factories. Its most important members:
| Member | Description |
|---|---|
factory | NodeFactory — creates and updates AST nodes |
getCompilerOptions() | Compiler options for the current build |
getEmitResolver() | Semantic query interface from the type checker |
getEmitHelperFactory() | Factory for emit helper expressions |
startLexicalEnvironment() | Begin collecting hoisted declarations |
endLexicalEnvironment() | Flush hoisted declarations as statements |
hoistVariableDeclaration(name) | Hoist a var to the enclosing function scope |
enableSubstitution(kind) | Register a SyntaxKind for just-in-time substitution during printing |
onSubstituteNode | Callback invoked by the printer to substitute a node at print time |
onEmitNode | Callback invoked by the printer around a node's emission |
readEmitHelpers() | Retrieve all accumulated emit helpers for attachment to the file |
Sources: src/compiler/transformer.ts271-314
NodeFactoryNodeFactory provides methods to construct new AST nodes and updateXxx(original, ...) methods that return the original node if no arguments differ, otherwise a new node with original set as its .original property.
Each transformer destructures what it needs from context:
Sources: src/compiler/transformers/ts.ts236-243 src/compiler/transformers/es2015.ts488-496
Transformers navigate and transform the AST using a set of visitor utilities:
| Function | Description |
|---|---|
visitNode(node, visitor, test?) | Visit a single node; returns the transformed node or undefined |
visitNodes(nodes, visitor, test?, start?, count?) | Visit a NodeArray; returns a new array if any node changes |
visitEachChild(node, visitor, context) | Visit every child of a node using the appropriate child-visiting logic |
visitFunctionBody(body, visitor, context) | Visit a function body inside a fresh lexical environment |
visitParameterList(params, visitor, context) | Visit parameters inside a parameter-scoped lexical environment |
The return type of a visitor is VisitResult<Node>, which can be a single node, an array of nodes (statement expansion), or undefined (elision).
A typical transformer uses TransformFlags on each node to fast-path through subtrees that contain no relevant syntax:
Sources: src/compiler/transformers/esnext.ts105-126 src/compiler/transformers/ts.ts382-396
Every Node carries a transformFlags: TransformFlags bitmask. Transformers use these to avoid descending into subtrees that contain no syntax they care about.
| Flag | Meaning |
|---|---|
ContainsTypeScript | Subtree contains TypeScript-only syntax |
ContainsES2015 | Subtree contains ES2015 syntax (classes, arrow functions, etc.) |
ContainsESNext | Subtree contains ESNext syntax (e.g., using declarations) |
ContainsDynamicImport | Contains a dynamic import() call |
Sources: src/compiler/transformers/ts.ts194 src/compiler/transformers/esnext.ts106-108
Emit helpers are reusable runtime functions injected into the output (e.g., __awaiter, __generator, __extends). They are requested via context.addEmitHelpers(node, helpers) or the EmitHelperFactory.
When --importHelpers is set, helpers are replaced with imports from tslib instead of inline definitions.
Sources: src/compiler/transformers/ts.ts4-5 src/compiler/transformers/es2017.ts5-6 src/compiler/transformers/generators.ts3-4
Some transformers alter identifiers or expressions at print time (e.g., replacing an enum member reference with its constant value). This is handled via:
onSubstituteNode(hint, node) — called by the printer before emitting a node registered with enableSubstitution(kind).onEmitNode(hint, node, emitCallback) — called by the printer around a registered node kind.For example, transformTypeScript uses substitution for namespace exports and enum members.
Sources: src/compiler/transformers/ts.ts252-262 src/compiler/transformers/module/module.ts205-214
getScriptTransformers assembles the ordered transformer list based on CompilerOptions.
Diagram: Script Transformer Selection
Sources: src/compiler/transformer.ts127-190
Covers the core mechanics of the pipeline, including the TransformationContext, the sequential execution of TransformerFactory chains, and how NodeFactory is used to maintain node identity and source maps.
Details transformTypeScript, which erases type annotations, handles enums, namespaces, parameter properties, and elides unused imports.
For details, see TypeScript Transformation.
Details how ES modules are converted to CommonJS, AMD, UMD, or SystemJS formats.
For details, see Module Transformation.
Details the version-specific transformers (e.g., transformES2015, transformES2017) that rewrite features like async/await, generators, and classes for older environments.
For details, see ECMAScript Downleveling.
Sources: src/compiler/transformer.ts53-73
Refresh this wiki