diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts
index f7c20e74d6717..991cab51c252a 100644
--- a/src/compiler/transformers/es2015.ts
+++ b/src/compiler/transformers/es2015.ts
@@ -145,7 +145,15 @@ namespace ts {
         loopOutParameters: LoopOutParameter[];
     }
 
-    type LoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement;
+    type DirectLoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement;
+    type TransformedLoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts, initializerFunction: IterationStatementPartFunction<VariableDeclarationList> | undefined, bodyFunction: IterationStatementPartFunction<Statement[]>) => Statement;
+
+    interface IterationStatementPartFunction<T> {
+        functionName: Identifier;
+        functionDeclaration: Statement;
+        containsYield: boolean;
+        part: T;
+    }
 
     // Facts we track as we traverse the tree
     const enum HierarchyFacts {
@@ -2284,9 +2292,9 @@ namespace ts {
             }
         }
 
-        function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter) {
+        function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertDirectly?: DirectLoopConverter, convertWithTransform?: TransformedLoopConverter) {
             const ancestorFacts = enterSubtree(excludeFacts, includeFacts);
-            const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, ancestorFacts, convert);
+            const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, ancestorFacts, convertDirectly, convertWithTransform);
             exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
             return updated;
         }
@@ -2322,19 +2330,23 @@ namespace ts {
                 HierarchyFacts.ForInOrForOfStatementExcludes,
                 HierarchyFacts.ForInOrForOfStatementIncludes,
                 node,
-                outermostLabeledStatement);
+                outermostLabeledStatement,
+                convertForInStatementForLoopDirectly,
+                convertForInStatementForLoopTransformed);
         }
 
         function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult<Statement> {
+            const convert = compilerOptions.downlevelIteration ? convertForOfStatementForIterable : convertForOfStatementForArray;
             return visitIterationStatementWithFacts(
                 HierarchyFacts.ForInOrForOfStatementExcludes,
                 HierarchyFacts.ForInOrForOfStatementIncludes,
                 node,
                 outermostLabeledStatement,
-                compilerOptions.downlevelIteration ? convertForOfStatementForIterable : convertForOfStatementForArray);
+                convert,
+                convert);
         }
 
-        function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) {
+        function convertForStatementHead(node: ForInStatement | ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) {
             const statements: Statement[] = [];
             const initializer = node.initializer;
             if (isVariableDeclarationList(initializer)) {
@@ -2433,6 +2445,77 @@ namespace ts {
             );
         }
 
+        function convertForInStatementForLoopDirectly(node: ForInStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[]): Statement {
+            // The following ES2015 code:
+            //
+            //    for (var [a, b] in expr) { }
+            //
+            // should be emitted as
+            //
+            //    for (var _a in expr) {
+            //        var a = _a[0], b = _a[1];
+            //    }
+            //
+            // where _a is a temp emitted to capture the LHS binding.
+            const initializerBinding = getForInInitializerBindingDeclaration(node);
+            if (initializerBinding) {
+                return convertForInStatementWithInitializerBinding(node, convertedLoopBodyStatements, initializerBinding);
+            }
+
+            return factory.restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement, convertedLoopState && resetLabel);
+        }
+
+        function convertForInStatementForLoopTransformed(node: ForInStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[], _ancestorFacts: HierarchyFacts, initializerFunction: IterationStatementPartFunction<VariableDeclarationList> | undefined, bodyFunction: IterationStatementPartFunction<Statement[]>): Statement {
+            // The following ES2015 code:
+            //
+            //    for (let [a, b] in expr) { ... }
+            //
+            // should be emitted as
+            //
+            //    var _loop_1 = function (_a) {
+            //      var a = _a[0], b = _a[1];
+            //      ...
+            //    }
+            //    for (var _a in expr) {
+            //        _loop_1(a);
+            //    }
+            //
+            // where _a is a temp emitted to capture the LHS binding.
+            const initializerBinding = getForInInitializerBindingDeclaration(node);
+            if (initializerBinding) {
+                return convertForInStatementWithInitializerBinding(node, convertedLoopBodyStatements, initializerBinding);
+            }
+
+            const clone = convertIterationStatementCore(node, initializerFunction, factory.createBlock(bodyFunction.part, /*multiLine*/ true));
+            return factory.restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
+        }
+
+        function convertForInStatementWithInitializerBinding(node: ForInStatement, convertedLoopBodyStatements: Statement[], _initializerBinding: VariableDeclaration) {
+            const tempInitializer = factory.createTempVariable(/*recordTempVariable*/ undefined);
+
+            return factory.createForInStatement(
+                factory.createVariableDeclarationList([factory.createVariableDeclaration(tempInitializer)]),
+                node.expression,
+                convertForStatementHead(
+                    node,
+                    tempInitializer,
+                    convertedLoopBodyStatements,
+                )
+            );
+        }
+
+        function getForInInitializerBindingDeclaration(node: ForInStatement) {
+            if (!isVariableDeclarationList(node.initializer) || node.initializer.declarations.length === 0) {
+                return undefined;
+            }
+
+            const declaration = node.initializer.declarations[0];
+
+            return isArrayBindingPattern(declaration.name) || isObjectBindingPattern(declaration.name)
+                ? declaration
+                : undefined;
+        }
+
         function convertForOfStatementForArray(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[]): Statement {
             // The following ES6 code:
             //
@@ -2488,7 +2571,7 @@ namespace ts {
                         node.expression
                     ),
                     /*incrementor*/ setTextRange(factory.createPostfixIncrement(counter), node.expression),
-                    /*statement*/ convertForOfStatementHead(
+                    /*statement*/ convertForStatementHead(
                         node,
                         factory.createElementAccessExpression(rhsReference, counter),
                         convertedLoopBodyStatements
@@ -2536,7 +2619,7 @@ namespace ts {
                         ),
                         /*condition*/ factory.createLogicalNot(factory.createPropertyAccessExpression(result, "done")),
                         /*incrementor*/ factory.createAssignment(result, next),
-                        /*statement*/ convertForOfStatementHead(
+                        /*statement*/ convertForStatementHead(
                             node,
                             factory.createPropertyAccessExpression(result, "value"),
                             convertedLoopBodyStatements
@@ -2731,7 +2814,7 @@ namespace ts {
             }
         }
 
-        function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convert?: LoopConverter): VisitResult<Statement> {
+        function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convertDirectly?: DirectLoopConverter, convertWithTransform?: TransformedLoopConverter): VisitResult<Statement> {
             if (!shouldConvertIterationStatement(node)) {
                 let saveAllowedNonLabeledJumps: Jump | undefined;
                 if (convertedLoopState) {
@@ -2741,8 +2824,8 @@ namespace ts {
                     convertedLoopState.allowedNonLabeledJumps = Jump.Break | Jump.Continue;
                 }
 
-                const result = convert
-                    ? convert(node, outermostLabeledStatement, /*convertedLoopBodyStatements*/ undefined, ancestorFacts)
+                const result = convertDirectly
+                    ? convertDirectly(node, outermostLabeledStatement, /*convertedLoopBodyStatements*/ undefined, ancestorFacts)
                     : factory.restoreEnclosingLabel(
                         isForStatement(node) ? visitEachChildOfForStatement(node) : visitEachChild(node, visitor, context),
                         outermostLabeledStatement,
@@ -2776,8 +2859,8 @@ namespace ts {
 
             let loop: Statement;
             if (bodyFunction) {
-                if (convert) {
-                    loop = convert(node, outermostLabeledStatement, bodyFunction.part, ancestorFacts);
+                if (convertWithTransform) {
+                    loop = convertWithTransform(node, outermostLabeledStatement, bodyFunction.part, ancestorFacts, initializerFunction, bodyFunction);
                 }
                 else {
                     const clone = convertIterationStatementCore(node, initializerFunction, factory.createBlock(bodyFunction.part, /*multiLine*/ true));
@@ -2981,13 +3064,6 @@ namespace ts {
             }
         }
 
-        interface IterationStatementPartFunction<T> {
-            functionName: Identifier;
-            functionDeclaration: Statement;
-            containsYield: boolean;
-            part: T;
-        }
-
         function createOutVariable(p: LoopOutParameter) {
             return factory.createVariableDeclaration(p.originalName, /*exclamationToken*/ undefined, /*type*/ undefined, p.outParamName);
         }
diff --git a/tests/baselines/reference/for-inStatementsDestructuring.errors.txt b/tests/baselines/reference/for-inStatementsDestructuring.errors.txt
index e54f2c93272a3..f324d60738137 100644
--- a/tests/baselines/reference/for-inStatementsDestructuring.errors.txt
+++ b/tests/baselines/reference/for-inStatementsDestructuring.errors.txt
@@ -1,10 +1,44 @@
 tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(1,10): error TS2461: Type 'string' is not an array type.
 tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(1,10): error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
+tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(2,10): error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
+tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(2,12): error TS2339: Property 'a' does not exist on type 'String'.
+tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(2,15): error TS2339: Property 'b' does not exist on type 'String'.
+tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(4,10): error TS2461: Type 'string' is not an array type.
+tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(4,10): error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
+tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(8,10): error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
+tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(8,12): error TS2339: Property 'a' does not exist on type 'String'.
+tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts(8,15): error TS2339: Property 'b' does not exist on type 'String'.
 
 
-==== tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts (2 errors) ====
+==== tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts (10 errors) ====
     for (var [a, b] in []) {}
              ~~~~~~
 !!! error TS2461: Type 'string' is not an array type.
              ~~~~~~
-!!! error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
\ No newline at end of file
+!!! error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
+    for (var { a, b } in []) {}
+             ~~~~~~~~
+!!! error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
+               ~
+!!! error TS2339: Property 'a' does not exist on type 'String'.
+                  ~
+!!! error TS2339: Property 'b' does not exist on type 'String'.
+    
+    for (let [a, b] in []) {
+             ~~~~~~
+!!! error TS2461: Type 'string' is not an array type.
+             ~~~~~~
+!!! error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
+        (() => a + b);
+    }
+    
+    for (let { a, b } in []) {
+             ~~~~~~~~
+!!! error TS2491: The left-hand side of a 'for...in' statement cannot be a destructuring pattern.
+               ~
+!!! error TS2339: Property 'a' does not exist on type 'String'.
+                  ~
+!!! error TS2339: Property 'b' does not exist on type 'String'.
+        (() => a + b);
+    }
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/for-inStatementsDestructuring.js b/tests/baselines/reference/for-inStatementsDestructuring.js
index e5e00d5b3ab56..f490e787b22ec 100644
--- a/tests/baselines/reference/for-inStatementsDestructuring.js
+++ b/tests/baselines/reference/for-inStatementsDestructuring.js
@@ -1,5 +1,34 @@
 //// [for-inStatementsDestructuring.ts]
-for (var [a, b] in []) {}
+for (var [a, b] in []) {}
+for (var { a, b } in []) {}
+
+for (let [a, b] in []) {
+    (() => a + b);
+}
+
+for (let { a, b } in []) {
+    (() => a + b);
+}
+
 
 //// [for-inStatementsDestructuring.js]
-for (var _a = void 0, a = _a[0], b = _a[1] in []) { }
+for (var _a in []) {
+    var a = _a[0], b = _a[1];
+}
+for (var _b in []) {
+    var a = _b.a, b = _b.b;
+}
+var _loop_1 = function (a_1, b_1) {
+    (function () { return a_1 + b_1; });
+};
+for (var _c in []) {
+    var a_1 = _c[0], b_1 = _c[1];
+    _loop_1(a_1, b_1);
+}
+var _loop_2 = function (a_2, b_2) {
+    (function () { return a_2 + b_2; });
+};
+for (var _d in []) {
+    var a_2 = _d.a, b_2 = _d.b;
+    _loop_2(a_2, b_2);
+}
diff --git a/tests/baselines/reference/for-inStatementsDestructuring.symbols b/tests/baselines/reference/for-inStatementsDestructuring.symbols
index fff70d63bd353..04c3a07077349 100644
--- a/tests/baselines/reference/for-inStatementsDestructuring.symbols
+++ b/tests/baselines/reference/for-inStatementsDestructuring.symbols
@@ -1,5 +1,27 @@
 === tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts ===
 for (var [a, b] in []) {}
->a : Symbol(a, Decl(for-inStatementsDestructuring.ts, 0, 10))
->b : Symbol(b, Decl(for-inStatementsDestructuring.ts, 0, 12))
+>a : Symbol(a, Decl(for-inStatementsDestructuring.ts, 0, 10), Decl(for-inStatementsDestructuring.ts, 1, 10))
+>b : Symbol(b, Decl(for-inStatementsDestructuring.ts, 0, 12), Decl(for-inStatementsDestructuring.ts, 1, 13))
+
+for (var { a, b } in []) {}
+>a : Symbol(a, Decl(for-inStatementsDestructuring.ts, 0, 10), Decl(for-inStatementsDestructuring.ts, 1, 10))
+>b : Symbol(b, Decl(for-inStatementsDestructuring.ts, 0, 12), Decl(for-inStatementsDestructuring.ts, 1, 13))
+
+for (let [a, b] in []) {
+>a : Symbol(a, Decl(for-inStatementsDestructuring.ts, 3, 10))
+>b : Symbol(b, Decl(for-inStatementsDestructuring.ts, 3, 12))
+
+    (() => a + b);
+>a : Symbol(a, Decl(for-inStatementsDestructuring.ts, 3, 10))
+>b : Symbol(b, Decl(for-inStatementsDestructuring.ts, 3, 12))
+}
+
+for (let { a, b } in []) {
+>a : Symbol(a, Decl(for-inStatementsDestructuring.ts, 7, 10))
+>b : Symbol(b, Decl(for-inStatementsDestructuring.ts, 7, 13))
+
+    (() => a + b);
+>a : Symbol(a, Decl(for-inStatementsDestructuring.ts, 7, 10))
+>b : Symbol(b, Decl(for-inStatementsDestructuring.ts, 7, 13))
+}
 
diff --git a/tests/baselines/reference/for-inStatementsDestructuring.types b/tests/baselines/reference/for-inStatementsDestructuring.types
index 547e54a574195..ce8518fcb60fd 100644
--- a/tests/baselines/reference/for-inStatementsDestructuring.types
+++ b/tests/baselines/reference/for-inStatementsDestructuring.types
@@ -4,3 +4,34 @@ for (var [a, b] in []) {}
 >b : any
 >[] : undefined[]
 
+for (var { a, b } in []) {}
+>a : any
+>b : any
+>[] : undefined[]
+
+for (let [a, b] in []) {
+>a : any
+>b : any
+>[] : undefined[]
+
+    (() => a + b);
+>(() => a + b) : () => any
+>() => a + b : () => any
+>a + b : any
+>a : any
+>b : any
+}
+
+for (let { a, b } in []) {
+>a : any
+>b : any
+>[] : undefined[]
+
+    (() => a + b);
+>(() => a + b) : () => any
+>() => a + b : () => any
+>a + b : any
+>a : any
+>b : any
+}
+
diff --git a/tests/baselines/reference/for-inStatementsDestructuring2.js b/tests/baselines/reference/for-inStatementsDestructuring2.js
index 41a6d30919f50..5c384b1c9dfa9 100644
--- a/tests/baselines/reference/for-inStatementsDestructuring2.js
+++ b/tests/baselines/reference/for-inStatementsDestructuring2.js
@@ -2,4 +2,6 @@
 for (var {a, b} in []) {}
 
 //// [for-inStatementsDestructuring2.js]
-for (var _a = void 0, a = _a.a, b = _a.b in []) { }
+for (var _a in []) {
+    var a = _a.a, b = _a.b;
+}
diff --git a/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js b/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js
index 42cafa5e355a0..8abe7764586b0 100644
--- a/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js
+++ b/tests/baselines/reference/jsDeclarationsSubclassWithExplicitNoArgumentConstructor.js
@@ -23,6 +23,8 @@ var __extends = (this && this.__extends) || (function () {
         return extendStatics(d, b);
     };
     return function (d, b) {
+        if (typeof b !== "function" && b !== null)
+            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
         extendStatics(d, b);
         function __() { this.constructor = d; }
         d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
diff --git a/tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts b/tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts
index 94868ef3bd62e..d73963a82b51e 100644
--- a/tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts
+++ b/tests/cases/conformance/statements/for-inStatements/for-inStatementsDestructuring.ts
@@ -1 +1,10 @@
-for (var [a, b] in []) {}
\ No newline at end of file
+for (var [a, b] in []) {}
+for (var { a, b } in []) {}
+
+for (let [a, b] in []) {
+    (() => a + b);
+}
+
+for (let { a, b } in []) {
+    (() => a + b);
+}