Repository: TypeScript
Issue: Implicit Symbol.iterator call in for..of loops / spread destructuring doesn't infer `this` generic type parameter
Labels: Suggestion,Experience Enhancement,Has Repro

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Even if you think you've found a *bug*, please read the FAQ first, especially the Common "Bugs" That Aren't Bugs section!

Please help us by doing the following steps before logging an issue:
  * Search: https://github.com/Microsoft/TypeScript/search?type=Issues
  * Read the FAQ: https://github.com/Microsoft/TypeScript/wiki/FAQ

Please fill in the *entire* template below.
-->

<!--
Please try to reproduce the issue with the latest published version. It may have already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly
-->
**TypeScript Version:**  4.0.0-dev.20200507

<!-- Search terms you tried before logging this (so others can find this issue more easily) -->
**Search Terms:** Symbol.iterator type parameter implicit calling for..of loops object spread destructuring this generic

**Code**

What follows is 3 different ways of iterating over an object using a custom-made iterator. However, using `Symbol.iterator` implicitly via the for..of loop fails to produce the same behavior:

```ts
const obj = {
	x: 1,
	y: 2,
	z: 3,
	*[Symbol.iterator]<T extends object>(
		this: T,
	): Generator<NonNullable<{ [K in keyof T]: [K, NonNullable<T[K]>] }[keyof T]>, void, unknown> {
		for (const entry of Object.entries(this)) yield entry as never;
	},
};

{
	const iter = obj[Symbol.iterator]();

	for (let result = iter.next(); !result.done; result = iter.next()) {
		const { value } = result;
		value; // ["x", number] | ["y", number] | ["z", number]
	}
}

for (const value of obj[Symbol.iterator]()) {
	value; // ["x", number] | ["y", number] | ["z", number]
}

for (const value of obj) {
	value; // NonNullable<{ [K in keyof T]: [K, NonNullable<T[K]>]; }[keyof T]>
	// bad! This should be ["x", number] | ["y", number] | ["z", number]
}

// also, spread destructuring suffers from the same problem!
const values = [...obj]; // Array<NonNullable<{ [K in keyof T]: [K, NonNullable<T[K]>]; }[keyof T]>>
// bad! This should be Array<["x", number] | ["y", number] | ["z", number]>
```

**Expected behavior:** `for (const value of obj)` should implicitly do the type equivalent of calling our iterator symbol, i.e. `for (const value of obj[Symbol.iterator]())`. That means our type parameter should be correctly inferred like so: `obj[Symbol.iterator]<T>(this: T)`.

**Actual behavior:** `T` cannot be inferred as the local `this` type, so all derivative types cannot be evaluated and the type stays as its generic version.

[**Playground Link**](https://www.typescriptlang.org/play/index.html?ts=4.0.0-dev.20200506#code/MYewdgzgLgBCBGArGBeGBvAsAKAJAA8AuGARgBodcBPYgJgrwC9iBmB3AKgG0BlKgW3ggANgDoAllACmAJwCGUEDIC6AHgAqMKfmlgAJhDhIpwKAD4AFJVxQAFuIjF17AJTEA4lLCyFS1QDlwfwBXYWE5eGEpVXQYLgBpGHEwGABrKSoQADMYdWViBLIYQLAQsIiojQTlM2UYAF8udMycvLMigDcQcT0i4LBUsBAAdzAzDGsspRgLUEhYLygZKjgcgHljU1FFmXEpCAs7BxcXGCo94T0tMCWVuUNvDtkAbkp6hnrX7BwsPDnoJLSGSoIyIXgCIRiSQ+RQqCwuL6UKbAixRWAyfahWBoaEyUTeHTw54wACEGIgWNEenAUmJ5KxINx+O0UHhp1+uFw-1gsQ6cmEwSkDRB9OEUC+nL5AtpMAA9LK4gAifCKopgYKCWR1AA+Sqoqpg6s1Khguq4isYBqN8C1bxw9RwOGRM25MClgtWoPBghEEiBvjhJwmeHdMvlSpVao1NpNZsV+qjxp1SstiZjyntjuwztm4ABoc9CEQ7MooeJ4ZKZXCkWisQSSRSzWyuXycXiRUroWrlXU1VqxMaTdaNUo4fgcj0JNy9kMEFsIFCVxtEat0a1pr1q6TG-NqcNa5Ume+2FdocMaC4oivReU5YVAEEZPIqAEgl2KrW2w20hlm3kCu2xRvuUNZVPENS3g0TS-sOZhmDgY4TlO6gzjAc4LpcMDLo+z6qOakb7tucYJoR6Y7haW7pmYQA) <!-- A link to a TypeScript Playground "Share" link which demonstrates this behavior -->

**Related Issues:** <!-- Did you find other bugs that looked similar? --> n/a