The emitter is the final stage of the TypeScript compilation pipeline. It takes a type-checked AST (or a set of them, in the case of --outFile mode), applies a transformer pipeline to convert TypeScript-specific syntax into target-compatible JavaScript, and then writes the output: JavaScript files, declaration files (.d.ts), and source maps.
This page covers src/compiler/emitter.ts and its interactions with the transformer infrastructure. For the transformer pipeline itself, see 3. Transformation Pipeline. For how the Program object initiates emission, see 2.6. Program and Compilation.
The emit process has two distinct phases:
TransformerFactory functions. Each transformer rewrites TypeScript-specific or downlevel syntax into forms appropriate for the target JavaScript version and module system.Printer, which serializes nodes into text, interleaving source positions for source map generation.Emit Pipeline
Sources: src/compiler/emitter.ts446-479 src/compiler/program.ts66-68
emitFilesThe primary internal entry point is emitFiles, defined in src/compiler/emitter.ts and called by Program.emit() in src/compiler/program.ts. It receives an EmitResolver, an EmitHost, and an EmitTransformers object bundling the configured transformer factories.
forEachEmittedFileforEachEmittedFile src/compiler/emitter.ts446-479 iterates over every file that is expected to produce output. For single-file-out (--outFile) mode, it creates a Bundle node. Otherwise, it iterates each SourceFile individually. For each file, it computes the output paths via getOutputPathsFor and calls the provided action.
| Output file type | Condition |
|---|---|
.js / .mjs / .cjs | emitDeclarationOnly is false |
.js.map | sourceMap or inlineSourceMap is set |
.d.ts | declaration or emitDeclarationOnly is set |
.d.ts.map | declarationMap is set |
.tsbuildinfo | incremental compilation or tscBuild is set |
Sources: src/compiler/emitter.ts446-504
The Printer interface is defined in src/compiler/types.ts. An instance is created by calling createPrinter(options, handlers) in src/compiler/emitter.ts.
Printer and its collaborators
Sources: src/compiler/types.ts4446-4475 src/compiler/emitter.ts1-425
Inside createPrinter, the core recursive function is pipelineEmitWithHint(hint, node). Before calling the actual node emitter, it:
onBeforeEmitNode from PrintHandlers (used by transformers for bookkeeping).substituteNode from PrintHandlers, which allows transformers to swap out a node at emit time.onEmitNode from PrintHandlers (transformers use this to inject helper prologues, etc.).emitFunctionDeclaration, emitClassDeclaration).onAfterEmitNode.This hook architecture allows the transformer pipeline to intercept every node in a non-destructive way.
ListFormatWhen emitting node arrays (parameters, arguments, type parameters, etc.), the printer uses the ListFormat bitfield enum from src/compiler/types.ts. Key flags include:
| Flag group | Examples |
|---|---|
| Delimiter | CommaDelimited, BarDelimited, AmpersandDelimited, SemicolonDelimited |
| Whitespace | SpaceBetweenBraces, Indented, MultiLine, SingleLine |
| Brackets | Braces, Brackets, Parenthesis, AngleBrackets |
| Special | NoTrailingNewLine, OptionalIfEmpty, PreferNewLine, AllowTrailingComma |
Sources: src/compiler/types.ts4482-4581
EmitFlags is a bitfield enum on src/compiler/types.ts that is stored on the EmitNode sidecar attached to each AST node (rather than directly on the node). It controls per-node printer behavior without mutating the original parsed tree.
Selected EmitFlags
| Flag | Effect |
|---|---|
NoLeadingComments | Suppress leading comment emit for the node |
NoTrailingComments | Suppress trailing comment emit |
SingleLine | Force single-line output |
MultiLine | Force multi-line output |
NoIndentation | Suppress indentation increase for children |
AsyncFunctionBody | Node is the body of an async function |
ReuseTempVariableScope | Reuse outer temp scope instead of a new one |
CustomPrologue | Statement is a custom prologue emitted before hoisted declarations |
NoHoisting | Prevent the declaration from being hoisted |
HasEndOfDeclarationMarker | End-of-declaration marker for multi-statement transforms |
Iterator | Iterate in a for-of without Symbol.iterator lookup |
NoAsciiEscaping | Emit unicode characters directly instead of as escape sequences |
The helpers setEmitFlags, addEmitFlags, and getEmitFlags in src/compiler/utilities.ts manipulate these flags through the EmitNode sidecar.
Sources: src/compiler/types.ts4602-4660 src/compiler/utilities.ts5-6
EmitHint is passed as the first argument to pipelineEmitWithHint and to the substituteNode / onEmitNode hooks in PrintHandlers. It tells the printer what syntactic role the node occupies so the correct emit path is taken.
| Value | Usage |
|---|---|
Unspecified | Default; the printer determines the path from node.kind |
Expression | Emit the node as an expression (may add parentheses) |
SourceFile | Emit as a full source file |
MappedTypeParameter | Emit as a mapped type's TypeParameter |
EmbeddedStatement | Emit as a statement inside another statement |
IdentifierName | Emit as a plain identifier without keyword checks |
JsxAttributeValue | Emit in a JSX attribute value context |
Sources: src/compiler/types.ts4584-4600
These two interfaces decouple the emitter from the rest of the compiler.
EmitHost (src/compiler/types.ts) is typically implemented by Program. It provides:
getSourceFiles() – the set of source filesgetCompilerOptions() – compiler optionswriteFile() – the actual file write callbackgetCommonSourceDirectory(), getCanonicalFileName(), path helpersisEmitBlocked(file) – whether a given file's emit has been suppressedEmitResolver (src/compiler/types.ts) is created by the type checker and answers semantic questions needed during emit:
isDeclarationVisible(node) – needed by the declaration transformergetReferencedExportContainer(node) – for export alias resolutionisValueAliasDeclaration(node), isReferencedAliasDeclaration(node) – import elisiongetConstantValue(node) – for const enum inlininggetTypeReferenceSerializationKind(node) – for decorator metadatacollectLinkedAliases(node) – for type-only importsSources: src/compiler/types.ts4311-4416 src/compiler/checker.ts166
Before printing, transformNodes (defined in src/compiler/transformer.ts, called from emitter.ts) applies the full sequence of built-in and user-provided transformers. The printer's PrintHandlers are wired up from the TransformationResult so that substituteNode and onEmitNode delegate to each transformer that registered hooks.
Relationship between transformers and the printer
The built-in transformers are applied in this order (for JS output):
src/compiler/transformers/ts.ts) – strips type annotations, handles decorators, emits const enum values.src/compiler/transformers/module/module.ts) – converts import/export to the target module format.Sources: src/compiler/emitter.ts77 src/compiler/transformers/ts.ts src/compiler/transformers/module/module.ts
Declaration file (.d.ts) generation runs as a separate transformer pass using the declarationTransformer. This transformer walks the type-checked AST and serializes inferred types through TypeChecker calls when explicit annotations are absent.
Sources: src/compiler/emitter.ts130 src/compiler/program.ts113
Source maps track the correspondence between positions in the emitted output and positions in the original TypeScript source. The emitter uses SourceMapGenerator (created by createSourceMapGenerator) to record these mappings.
Sources: src/compiler/emitter.ts55 src/compiler/sourcemap.ts
getOutputPathsFor and getOwnEmitOutputFilePath in emitter.ts compute where each output file goes based on outDir, rootDir, outFile, and the input file path. .tsbuildinfo path resolution is handled by getTsBuildInfoEmitOutputFilePath src/compiler/emitter.ts481-500
Sources: src/compiler/emitter.ts506-560
| Symbol | File | Role |
|---|---|---|
emitFiles | src/compiler/emitter.ts | Orchestrates the full emit for a Program |
createPrinter | src/compiler/emitter.ts | Factory for Printer instances |
Printer | src/compiler/types.ts | Interface for AST-to-text serialization |
EmitHost | src/compiler/types.ts | Abstracts file I/O and program data |
EmitResolver | src/compiler/types.ts | Semantic answers from type checker |
EmitFlags | src/compiler/types.ts | Per-node printer control flags |
EmitTextWriter | src/compiler/types.ts | Text buffer with indent tracking |
SourceMapGenerator | src/compiler/types.ts | Records position mappings |
Refresh this wiki