This document describes the ECMAScript downleveling transformers in the TypeScript compiler. These transformers convert modern JavaScript features from ES2015 through ESNext to older JavaScript versions (primarily ES5 and ES3) to ensure compatibility with older runtime environments.
ECMAScript downleveling occurs after TypeScript-specific syntax has been removed (see TypeScript Transformation) and before module format transformation (see Module Transformation). The downleveling transformers handle features like classes, arrow functions, destructuring, async/await, generators, and other modern JavaScript constructs.
Related Pages:
ECMAScript downleveling transformers are applied in reverse chronological order—from newest to oldest language versions. This ensures that newer features are transformed to intermediate forms that can then be further downleveled by older transformers.
Transformer Chain Diagram
Sources: getScriptTransformers logic in src/compiler/transformer.ts127-189 (implied by target checks).
transformES2015)The ES2015 transformer is the most comprehensive downleveling transformer, handling the majority of ES2015 (ES6) features. It transforms classes, arrow functions, destructuring patterns, for-of loops, spread operators, template literals, and block-scoped bindings.
Feature Transformation Overview
Sources: src/compiler/transformers/es2015.ts488-547 (visitor logic).
ES2015 classes are transformed into ES5 constructor functions with prototype assignments. The transformer handles:
extends clauseThe main entry point is visitClassDeclaration at src/compiler/transformers/es2015.ts880-975 which:
getClassFacts (e.g., if it has decorators or static properties).Arrow functions are transformed to regular function expressions, with special handling for lexical this binding.
Sources: src/compiler/transformers/es2015.ts1163-1191 (visitArrowFunction).
Destructuring patterns (both array and object) are flattened into sequential assignments. This is handled by the shared destructuring transformer.
Destructuring Flattening Example Flow
Sources: src/compiler/transformers/destructuring.ts99-195 (flattenDestructuringAssignment), src/compiler/transformers/es2015.ts2142-2217
For-of loops are transformed into traditional for loops that work with iterators.
Sources: src/compiler/transformers/es2015.ts1876-2090 (visitForOfStatement).
Block-scoped variables (let and const) are transformed to var declarations with special handling for loop closures. When a loop contains block-scoped bindings that are captured by closures and potentially modified, the transformer creates a per-iteration function to preserve correct binding semantics.
Sources: src/compiler/transformers/es2015.ts266-365 (Loop closure logic).
transformES2017)The ES2017 transformer primarily handles async/await syntax, transforming it into generator-based state machines with promise wrapping.
Async Function Transformation Flow
Sources: src/compiler/transformers/es2017.ts119-282 (transformES2017 and visitors).
For async methods with super calls, additional helpers (__asyncSuperHelper, __advancedAsyncSuperHelper) are emitted to properly handle super property access in the async context src/compiler/transformers/es2017.ts465-652
transformGenerators)The generator transformer converts generator functions into state machines that can be executed in ES5 environments.
The generator transformer works by:
.yield, .return, .br (break/jump), .try, .catch, .finally.__generator helper that manages iteration protocol.Sources: src/compiler/transformers/generators.ts336-2474 (state machine construction logic).
The main transformation function is transformGeneratorFunctionBody src/compiler/transformers/generators.ts666-760
transformESNext)The ESNext transformer handles features in the ESNext stage, currently focused on using declarations and explicit resource management.
Using Declaration Transformation
Sources: src/compiler/transformers/esnext.ts71-334 (transformESNext and visitSourceFile).
The transformer wraps code containing using declarations in try-finally blocks to ensure proper resource disposal, using the __addDisposableResource and __disposeResources helpers.
While this page focuses on ECMAScript version downleveling, these transformers often interact with module transformers. For example, the transformModule function in src/compiler/transformers/module/module.ts174-188 handles the conversion of ES modules to CommonJS, AMD, or UMD.
SystemJS modules have a unique shape handled in src/compiler/transformers/module/system.ts137-176 where the module body is wrapped in System.register.
Downleveling transformers rely on emit helpers—runtime functions injected into the output.
| Feature | Helper Functions | Purpose |
|---|---|---|
| Classes | __extends | Prototype chain inheritance |
| Async/Await | __awaiter, __generator | Manages generator execution and promises |
| Generators | __generator | State machine runtime |
| Async Generators | __asyncGenerator, __await | Combined async + generator runtime |
| Spread/Rest | __spreadArray, __rest, __assign | Object/Array operations |
| Using | __addDisposableResource, __disposeResources | Resource management |
Sources: src/compiler/transformers/es2015.ts src/compiler/transformers/es2017.ts src/compiler/transformers/generators.ts src/compiler/transformers/esnext.ts
Test baselines like tests/baselines/reference/emitter.asyncGenerators.functionDeclarations.es2015.js34-46 demonstrate the injection of __await and __asyncGenerator helpers into the generated JavaScript.
Refresh this wiki