Repository: babel/babel (TypeScript)

Issue:
[Bug]: local let variable is not captured in for..in loop
### 💻

- [ ] Would you like to work on a fix?

### How are you using Babel?

babel-loader (webpack)

### Input code

```js
function proxyObserver(component) {
  for (let key in component.properties)
    if (component.properties[key].observer) {
      let base = component.properties[key].observer;
      component.properties[key].observer = () => {
        // console.log("key", key);
        base.apply(this);
      };
    }

  return component;
}
```

### Configuration file name

_No response_

### Configuration

_No response_

### Current and expected behavior

local variable `base` is not captured into closure. note that when variable `key` is used in closure, it'll work as expected.

## current behavior
```js
function proxyObserver(component) {
  var _this = this;
  for (var key in component.properties) if (component.properties[key].observer) {
    var base = component.properties[key].observer;
    component.properties[key].observer = function () {
      // console.log("key", key);
      base.apply(_this);
    };
  }
  return component;
}
```

## expected behavior
```js
function proxyObserver(component) {
  var _this = this;
  var _loop = function _loop(key) {
    if (component.properties[key].observer) {
      var base = component.properties[key].observer;
      component.properties[key].observer = function () {
        // console.log("key", key);
        base.apply(_this);
      };
    }
  };
  for (var key in component.properties) {
    _loop(key);
  }
  return component;
}
```

### Environment

babel playground

### Possible solution

seem like only `for in` is not working

### Additional context

_No response_


Hints:
Hey @ele828! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant [Slack community](https://babeljs.slack.com) that typically always has someone willing to help. You can sign-up [here](https://slack.babeljs.io/) for an invite.

Patch:
diff --git a/packages/babel-plugin-transform-block-scoping/src/index.ts b/packages/babel-plugin-transform-block-scoping/src/index.ts
--- a/packages/babel-plugin-transform-block-scoping/src/index.ts
+++ b/packages/babel-plugin-transform-block-scoping/src/index.ts
@@ -57,12 +57,11 @@ export default declare((api, opts: Options) => {
           let bodyScope: Scope | null;
           if (body.isBlockStatement()) {
             bodyScope = body.scope;
-
-            const bindings = getLoopBodyBindings(path);
-            for (const binding of bindings) {
-              const { capturedInClosure } = getUsageInBody(binding, path);
-              if (capturedInClosure) markNeedsBodyWrap();
-            }
+          }
+          const bindings = getLoopBodyBindings(path);
+          for (const binding of bindings) {
+            const { capturedInClosure } = getUsageInBody(binding, path);
+            if (capturedInClosure) markNeedsBodyWrap();
           }
 
           const captured: string[] = [];


Test patch:
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/exec.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/exec.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/exec.js
@@ -0,0 +1,18 @@
+function proxyObserver(properties) {
+  for (let key in properties)
+    if (properties[key].observer) {
+      let base = properties[key].observer;
+      properties[key].observer = () => {
+        return base.apply(this);
+      };
+    }
+
+  return properties;
+}
+
+const results = proxyObserver([
+  { observer: () => 1 },
+  { observer: () => 2 },
+])
+expect(results[0].observer()).toBe(1)
+expect(results[1].observer()).toBe(2)
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/input.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/input.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/input.js
@@ -0,0 +1,23 @@
+function proxyObserver(component) {
+  for (let key in component.properties)
+    if (component.properties[key].observer) {
+      let base = component.properties[key].observer;
+      component.properties[key].observer = () => {
+        base.apply(this);
+      };
+    }
+
+  return component;
+}
+
+function proxyObserver2(component) {
+  for (let key of component.properties)
+    while (1) {
+      let base = component.properties[key].observer;
+      component.properties[key].observer = () => {
+        base.apply(this);
+      };
+    }
+
+  return component;
+}
diff --git a/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/output.js b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/output.js
new file mode 100644
--- /dev/null
+++ b/packages/babel-plugin-transform-block-scoping/test/fixtures/general/for-without-block/output.js
@@ -0,0 +1,30 @@
+function proxyObserver(component) {
+  var _this = this;
+  var _loop = function () {
+    if (component.properties[key].observer) {
+      var base = component.properties[key].observer;
+      component.properties[key].observer = function () {
+        base.apply(_this);
+      };
+    }
+  };
+  for (var key in component.properties) {
+    _loop();
+  }
+  return component;
+}
+function proxyObserver2(component) {
+  var _this2 = this;
+  for (var key of component.properties) {
+    var _loop2 = function () {
+      var base = component.properties[key].observer;
+      component.properties[key].observer = function () {
+        base.apply(_this2);
+      };
+    };
+    while (1) {
+      _loop2();
+    }
+  }
+  return component;
+}