microsoft / microsoft/TypeScript
Enumerating an enum: Wrong thing is allowed and right thing is not with with noImplicityAny
まだ誰も着手していません。
- 主要言語
- Go
- スター
- 111k
- フォーク
- 14.3k
- 平均マージ
- 1日 19時間
- マージ済み PR(30日)
- 117
説明
Consider this code:
enum Test1 {
One = 1,
Two = 2
}
enum Test2 {
One = "one",
Two = 2
}
enum Test3 {
One = "one",
Two = "two"
}
for (const key in Test1) {
const aValue = Test1[key];
console.log(aValue);
}
This code compiles but because in an enum a reverse value->key map is also set up for numeric values, the outcome is not what one would expect: 1, 2. It's: One, Two, 1, 2 instead. Similarly, replacing Test1 with Test2 in the for..in loop compiles but gives unexpected result: "Two", "one", 2. However, with Test3, for which the result would've been correct: "one", "two", there's a compile error with the noImplicitAny compiler option:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof Test3'.
No index signature with a parameter of type 'string' was found on type 'typeof Test3'.
This seems backwards of what the behavior should be: With Test1 and Test2, the compile should fail and it should succeed with Test3. If not that, the compile should either fail or succeed with all 3. FYI, the reason I noticed this was because converting an all numeric enum to all string enum caused compile failure for some other code that was using "for..in" which originally had a logical flaw which the compiler didn't catch but it's flagging it now when the logical flaw has (inadvertently) been fixed.
It seems like there are at least a couple of independent problems here.
-
With enums that have at least one numeric member (Test1 and Test2), the inferred type of loop variable (key) should ideally be the union of all keys and numeric values or at least string | number, not just string.
-
Indexing enums by a string (that cannot be narrowed down specific literals representing keys of an enum) should consistently return any. It may acceptable to return union type of all possible values: number for Test1, string|number for Test2 and string for Test3 and not string for Test1 and Test2 and any for Test3.
-
In addition to the issues above, a for..in over an enum should somehow be flagged and fail to compile regardless of noImplicitAny flag because it only yields the expected result in the enum has all string values but even with all string-enums, that would be fragile as adding a single numeric value to the enum will cause compile failures at that point. It should just not be allowed at least by default.
Issue #18409 seems related but not quite the same.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
まず、noImplicitAny を有効にして Test1、Test2、Test3 のスニペットを再現し、それぞれの enum の逆マッピング、for-in の結果、インデックスアクセスのエラーを比較します。次に、enum のインデックスアクセスと for-in に対するコンパイラの型推論を追跡します。issue で選択された動作が仕様として定められ、一貫して適用されていること(enum の反復を拒否すべきかどうかも含む)が完了条件です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- typescript
- 領域
- compilers
- issue の種類
- バグ
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 停滞
- 明瞭さ
- 説明が足りない
- 初心者へのやさしさ
- 25/100