Code Fix

上級

数値enumはObject.keys()で要素数が2倍になる(逆引きマッピングの副作用)

数値enumは、コンパイル後のJavaScriptオブジェクトに「メンバー名→値」だけでなく「値→メンバー名」の逆引きも自動的に持たせます。この副作用でObject.keys()を呼ぶと、メンバーの2倍の数のキーが返ってきます。

なぜエラーが出ないのか

出力: 4
(エラーなし)
TypeScriptは何も報告しません。型検査も構文も正しいためです
出力: 4
実際の挙動 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  enum Status {
 2    Active,
 3    Inactive,
 4  }
 5  console.log(Object.keys(Status).length                                     );
                                                         ^
出力: 4

数値enumはコンパイル後、メンバー名→値だけでなく値→メンバー名の逆引きも持ちます。Object.keys().lengthはメンバー数の2倍(4)になります。

直し方: lengthfilter(k => Number.isNaN(Number(k))).length にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  enum Level {
 2    Low,
 3    Mid,
 4    High,
 5  }
 6  console.log(Object.keys(Level).length                                     );
                                                        ^
出力: 6

Levelは3メンバーですが、逆引きマッピングの分も合わせてObject.keys().lengthは6になります。

直し方: lengthfilter(k => Number.isNaN(Number(k))).length にします。

この問題を解いてみる →

パターン3

 1  enum Direction {
 2    North,
 3    South,
 4    East,
 5    West,
 6  }
 7  console.log(Object.keys(Direction).length                                     );
                                                            ^
出力: 8

Directionは4メンバーです。逆引き分も含めるとObject.keys().lengthは8になります。

直し方: lengthfilter(k => Number.isNaN(Number(k))).length にします。

この問題を解いてみる →

よくある誤解

「enumはただのメンバー一覧を表す型のはず」という理解は、コンパイル後の実体までは説明していません。数値enumはコンパイル時にJavaScriptの通常のオブジェクトへ変換され、逆引き用のキーも一緒に埋め込まれます。

まとめ

数値enumはObject.keys()で要素数が2倍になる(逆引きマッピングの副作用)は上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)