Skip to content

Implicit Symbol.iterator call in for..of loops / spread destructuring doesn't infer this generic type parameter #38388

Open
@Validark

Description

@Validark

TypeScript Version: 4.0.0-dev.20200507

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:

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

Related Issues: n/a

Metadata

Metadata

Assignees

No one assigned

    Labels

    Experience EnhancementNoncontroversial enhancementsHas ReproThis issue has compiler-backed repros: https://aka.ms/ts-reprosSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions