microsoft / microsoft/TypeScript

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

オープン
#38,388 コメント 8 件 リアクション 4 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

Experience Enhancement Has Repro Suggestion
主要言語
Go
スター
111k
フォーク
14.3k
平均マージ
2日 4時間
マージ済み PR(30日)
132

説明

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

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

提供された TypeScript コードまたは Playground Link を使って問題を再現し、Symbol.iterator の明示的な呼び出しと for..of および spread による分割代入を比較します。コンパイラーによる暗黙的なイテレーター呼び出しの処理と、generic this の推論を追跡します。完了の条件は、2 つの暗黙的な形式が、明示的な呼び出しと同じタプル共用体を推論することです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
typescript
領域
compilers
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。