The Emitter
The emitter is the final stage of compilation, responsible for generating output files. Located in src/compiler/emitter.ts (273KB), it transforms the type-checked AST into JavaScript and declaration files.
Emit Entry Point
// 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
The emitter uses the resolver to query type information and applies transformers to modify the output.
Emit Process
Transform AST
Apply transformers to modify the syntax tree: // Transformers convert TypeScript features to JavaScript
// Example: async/await → generator functions (for ES5)
async function getData () {
return await fetch ( "/api" );
}
// Transformed to:
function getData () {
return __awaiter ( this , void 0 , void 0 , function* () {
return yield fetch ( "/api" );
});
}
Generate Code
Convert AST nodes to JavaScript text: // TypeScript input
interface User {
name : string ;
age : number ;
}
class UserManager {
getUser () : User {
return { name: "Alice" , age: 30 };
}
}
// JavaScript output (ES5)
var UserManager = /** @class */ ( function () {
function UserManager () {
}
UserManager . prototype . getUser = function () {
return { name: "Alice" , age: 30 };
};
return UserManager ;
}());
Create Declaration Files
Generate .d.ts files for type information: // Generated .d.ts file
interface User {
name : string ;
age : number ;
}
declare class UserManager {
getUser () : User ;
}
Generate Source Maps
Create mappings between output and source: {
"version" : 3 ,
"file" : "output.js" ,
"sourceRoot" : "" ,
"sources" : [ "input.ts" ],
"mappings" : "AAAA,IAAM,CAAC,GAAG,CAAC..."
}
TypeScript can emit different JavaScript module formats:
CommonJS
ES Modules
UMD
System
Node.js style modules: // Input
export function greet ( name : string ) {
return `Hello, ${ name } ` ;
}
// Output (CommonJS)
"use strict" ;
Object . defineProperty ( exports , "__esModule" , { value: true });
exports . greet = greet ;
function greet ( name ) {
return "Hello, " + name ;
}
Config: {
"compilerOptions" : {
"module" : "CommonJS"
}
}
ECMAScript modules: // Input
export function greet ( name : string ) {
return `Hello, ${ name } ` ;
}
// Output (ESNext)
export function greet ( name ) {
return `Hello, ${ name } ` ;
}
Config: {
"compilerOptions" : {
"module" : "ESNext"
}
}
Universal Module Definition: ( function ( factory ) {
if ( typeof module === "object" && typeof module . exports === "object" ) {
// CommonJS
var v = factory ( require , exports );
if ( v !== undefined ) module . exports = v ;
}
else if ( typeof define === "function" && define . amd ) {
// AMD
define ([ "require" , "exports" ], factory );
}
})( function ( require , exports ) {
"use strict" ;
Object . defineProperty ( exports , "__esModule" , { value: true });
// ...
});
Config: {
"compilerOptions" : {
"module" : "UMD"
}
}
SystemJS modules: System . register ([], function ( exports_1 , context_1 ) {
"use strict" ;
var greet ;
var __moduleName = context_1 && context_1 . id ;
return {
setters: [],
execute : function () {
exports_1 ( "greet" , greet = function ( name ) {
return "Hello, " + name ;
});
}
};
});
Config: {
"compilerOptions" : {
"module" : "System"
}
}
Emit Targets
The target option controls which JavaScript version is emitted:
ES3 Ancient JavaScript (IE8 and below)
Target Impact on Output
Classes
Arrow Functions
Async/Await
Destructuring
ES2015+ :class Point {
constructor ( x , y ) {
this . x = x ;
this . y = y ;
}
}
ES5 :var Point = /** @class */ ( function () {
function Point ( x , y ) {
this . x = x ;
this . y = y ;
}
return Point ;
}());
ES2015+ :const add = ( a , b ) => a + b ;
ES5 :var add = function ( a , b ) { return a + b ; };
ES2017+ :async function fetchData () {
return await fetch ( "/api" );
}
ES2015 :function fetchData () {
return __awaiter ( this , void 0 , void 0 , function* () {
return yield fetch ( "/api" );
});
}
ES5 :function fetchData () {
return __awaiter ( this , void 0 , void 0 , function () {
return __generator ( this , function ( _a ) {
switch ( _a . label ) {
case 0 : return [ 4 , fetch ( "/api" )];
case 1 : return [ 2 , _a . sent ()];
}
});
});
}
ES2015+ :ES5 :var x = point . x , y = point . y ;
Declaration Files
Declaration files (.d.ts) contain type information without implementation:
Generating Declarations
{
"compilerOptions" : {
"declaration" : true ,
"declarationMap" : true ,
"emitDeclarationOnly" : false
}
}
declaration Generate .d.ts files alongside JavaScript
declarationMap Generate source maps for declaration files
emitDeclarationOnly Emit only .d.ts files (skip JavaScript)
Declaration File Example
// source.ts
export class Calculator {
private value = 0 ;
add ( n : number ) : this {
this . value += n ;
return this ;
}
getResult () : number {
return this . value ;
}
}
export function multiply ( a : number , b : number ) : number {
return a * b ;
}
// source.d.ts (generated)
export declare class Calculator {
private value ;
add ( n : number ) : this ;
getResult () : number ;
}
export declare function multiply ( a : number , b : number ) : number ;
Source Maps
Source maps enable debugging TypeScript code in browsers:
Source Map Configuration
{
"compilerOptions" : {
"sourceMap" : true ,
"inlineSourceMap" : false ,
"inlineSources" : false ,
"sourceRoot" : "" ,
"mapRoot" : ""
}
}
Generate separate .js.map files: // output.js
var x = 1 ;
//# sourceMappingURL=output.js.map
Embed source map in JavaScript file: // output.js
var x = 1 ;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9u...
Include original TypeScript source in source map: {
"version" : 3 ,
"sources" : [ "input.ts" ],
"sourcesContent" : [ "const x: number = 1;" ],
"mappings" : "AAAA,IAAM,CAAC,GAAG,CAAC"
}
Transformers modify the AST before emission:
Type Erasure
Enum Transformation
Namespace Transformation
Decorator Transformation
Removes TypeScript-specific syntax: // Input
function greet ( name : string ) : string {
return `Hello, ${ name } ` ;
}
// Output
function greet ( name ) {
return `Hello, ${ name } ` ;
}
Converts enums to JavaScript objects: // Input
enum Color {
Red ,
Green ,
Blue
}
// Output
var Color ;
( function ( Color ) {
Color [ Color [ "Red" ] = 0 ] = "Red" ;
Color [ Color [ "Green" ] = 1 ] = "Green" ;
Color [ Color [ "Blue" ] = 2 ] = "Blue" ;
})( Color || ( Color = {}));
Converts namespaces to IIFEs: // Input
namespace Utils {
export function log ( msg : string ) {
console . log ( msg );
}
}
// Output
var Utils ;
( function ( Utils ) {
function log ( msg ) {
console . log ( msg );
}
Utils . log = log ;
})( Utils || ( Utils = {}));
Applies decorator metadata: // Input
@ sealed
class BugReport {
@ validate
title : string ;
}
// Output (simplified)
let BugReport = class BugReport {
};
__decorate ([
validate
], BugReport . prototype , "title" , void 0 );
BugReport = __decorate ([
sealed
], BugReport );
// Define a custom transformer
import ts from "typescript" ;
const transformer : ts . TransformerFactory < ts . SourceFile > = ( context ) => {
return ( sourceFile ) => {
const visitor = ( node : ts . Node ) : ts . Node => {
// Transform nodes here
if ( ts . isStringLiteral ( node )) {
return ts . factory . createStringLiteral (
node . text . toUpperCase ()
);
}
return ts . visitEachChild ( node , visitor , context );
};
return ts . visitNode ( sourceFile , visitor );
};
};
// Use with program
program . emit (
undefined ,
undefined ,
undefined ,
false ,
{ before: [ transformer ] }
);
Emit Options
Output Control
{
"compilerOptions" : {
"outDir" : "./dist" ,
"outFile" : "./bundle.js" ,
"removeComments" : true ,
"noEmit" : false ,
"noEmitOnError" : true
}
}
outDir Directory for output files
outFile Concatenate output into single file
removeComments Strip comments from output
noEmit Skip emit entirely (type checking only)
noEmitOnError Don’t emit if there are errors
JavaScript Emit Options
{
"compilerOptions" : {
"importHelpers" : true ,
"downlevelIteration" : true ,
"preserveConstEnums" : false ,
"removeComments" : false ,
"newLine" : "lf"
}
}
Import helper functions from tslib instead of inlining: // Without importHelpers
var __awaiter = ( this && this . __awaiter ) || function () { /* ... */ };
// With importHelpers
import { __awaiter } from "tslib" ;
Emit more accurate iteration for ES5/ES3: // Input
for ( const item of array ) { }
// With downlevelIteration (accurate)
for ( var _i = 0 , array_1 = array ; _i < array_1 . length ; _i ++ ) {
var item = array_1 [ _i ];
}
Keep const enum declarations in output: // Input
const enum E { A = 1 }
// Without preserve (inlined)
console . log ( 1 );
// With preserve (kept)
var E ;
( function ( E ) { E [ E [ "A" ] = 1 ] = "A" ; })( E || ( E = {}));
console . log ( 1 );
Emit Helpers
TypeScript uses helper functions for downleveling:
// Common helpers from emitter.ts
var __extends = ( this && this . __extends ) || /* ... */ ;
var __awaiter = ( this && this . __awaiter ) || /* ... */ ;
var __generator = ( this && this . __generator ) || /* ... */ ;
var __decorate = ( this && this . __decorate ) || /* ... */ ;
var __spreadArray = ( this && this . __spreadArray ) || /* ... */ ;
Use importHelpers: true to import from tslib instead of duplicating helpers: {
"compilerOptions" : {
"importHelpers" : true
}
}
Incremental Emit
TypeScript can store compilation state for faster rebuilds:
{
"compilerOptions" : {
"incremental" : true ,
"tsBuildInfoFile" : "./.tsbuildinfo"
}
}
The .tsbuildinfo file contains:
File hashes
Dependency graph
Emit signatures
Diagnostic information
Incremental compilation can dramatically speed up rebuilds by only recompiling changed files and their dependents.
Best Practices
Match Target to Environment Set target based on your runtime: {
"compilerOptions" : {
"target" : "ES2020" , // Modern browsers
"lib" : [ "ES2020" , "DOM" ]
}
}
Enable Source Maps Always generate source maps for debugging: {
"compilerOptions" : {
"sourceMap" : true
}
}
Use Declaration Maps For libraries, enable declaration maps: {
"compilerOptions" : {
"declaration" : true ,
"declarationMap" : true
}
}
Optimize Bundle Size Use importHelpers to reduce duplication: {
"compilerOptions" : {
"importHelpers" : true
}
}
Compiler Overview Learn about the full compilation pipeline
Type Checking Understand type validation