Map<K, V>
Map
はJavaScriptの組み込みAPIのひとつで、キーと値のペアを取り扱うためのオブジェクトです。Map
にはひとつのキーについてはひとつの値のみを格納できます。
Mapオブジェクトの作り方
Map
オブジェクトを作るにはMap
クラスをnew
します。たとえば、キーがstring
、値がnumber
のMap<string, number>
は次のように作ります。
ts
constmap = newMap <string, number>();map .set ("a", 1);console .log (map .get ("a"));
ts
constmap = newMap <string, number>();map .set ("a", 1);console .log (map .get ("a"));
コンストラクタにキーと値の[タプル型][K, V]
の配列[K, V][]
を渡すとMap<K, V>
オブジェクトが作られます。
📄️ タプル
TypeScriptの関数は1値のみ返却可能です。戻り値に複数の値を返したい時に、配列に返したいすべての値を入れて返すことがあります。なお次の関数の戻り値は定数になっていますが、実際は演算した結果だと解釈してください。
ts
constmap = newMap <string, number>([["a", 1],["b", 2],["c", 3],]);console .log (map );
ts
constmap = newMap <string, number>([["a", 1],["b", 2],["c", 3],]);console .log (map );
Map
の型変数を省略した場合、TypeScriptはコンストラクタ引数からMap<K, V>
の型を推論します。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);map ;
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);map ;
コンストラクタ引数を省略した場合、空のMap
が作られます。
ts
constmap = newMap <string, number>();console .log (map );
ts
constmap = newMap <string, number>();console .log (map );
型引数とコンストラクタ引数の両方を省略した場合、Map<any, any>
型になります。
ts
constmap = newMap ();
ts
constmap = newMap ();
Mapの型注釈
TypeScriptでMapの型注釈をする場合は、Map<string, number>
のようにMap要素の型を型変数に指定します。
ts
functiondoSomething (map :Map <string, number>) {}
ts
functiondoSomething (map :Map <string, number>) {}
Mapのキーは厳密等価で判定される
Map
のキーが同じかどうかは厳密等価(===
)で判定します。等価(==
)ではありません。
たとえば、null
とundefined
は等価ですが、厳密等価では等しくありません。
ts
console .log (null ==undefined );console .log (null ===undefined );
ts
console .log (null ==undefined );console .log (null ===undefined );
そのため、Map
はnull
とundefined
を異なるキーとみなします。
ts
constmap = newMap <any, any>([[null, 1]]);console .log (map .has (null));console .log (map .has (undefined ));
ts
constmap = newMap <any, any>([[null, 1]]);console .log (map .has (null));console .log (map .has (undefined ));
NaN
同士は厳密等価ではありませんが、例外的に同じキーとみなされます。
ts
console .log (NaN ===NaN );constmap = newMap <number, number>();map .set (NaN , 1);map .set (NaN , 2);console .log (map );
ts
console .log (NaN ===NaN );constmap = newMap <number, number>();map .set (NaN , 1);map .set (NaN , 2);console .log (map );
オブジェクトは等価でも厳密等価でもないため、別のキーとみなされます。
ts
console .log ({} == {});console .log ({} === {});constmap = newMap <object, number>();map .set ({}, 1);map .set ({}, 2);console .log (map );
ts
console .log ({} == {});console .log ({} === {});constmap = newMap <object, number>();map .set ({}, 1);map .set ({}, 2);console .log (map );
Mapの操作
要素をセットする - Map.prototype.set()
Map
にキーと値のペアを追加するにはset
メソッドを使います。
ts
constmap = newMap <string, number>();map .set ("a", 1);console .log (map );
ts
constmap = newMap <string, number>();map .set ("a", 1);console .log (map );
すでにキーがある場合は、値を上書きします。
ts
constmap = newMap ([["a", 1]]);map .set ("a", 5);console .log (map );
ts
constmap = newMap ([["a", 1]]);map .set ("a", 5);console .log (map );
値を取得する - Map.prototype.get()
Map
からキーをもとに要素を取得するにはget
メソッドを使います。
ts
constmap = newMap ([["a", 1]]);console .log (map .get ("a"));
ts
constmap = newMap ([["a", 1]]);console .log (map .get ("a"));
get
メソッドは、キーが存在しない場合、undefined
を返します。
ts
constmap = newMap ([["a", 1]]);console .log (map .get ("b"));
ts
constmap = newMap ([["a", 1]]);console .log (map .get ("b"));
Null合体演算子と組み合わせることによってget
メソッドで値を取得できなかったときにデフォルトの値を代入することができます。
ts
constmap = newMap ([["a", 1]]);console .log (map .get ("b") ?? 2);
ts
constmap = newMap ([["a", 1]]);console .log (map .get ("b") ?? 2);
特定の要素を削除する - Map.prototype.delete()
Map
からキーを指定して要素を削除するにはdelete
メソッドを使います。
ts
constmap = newMap ([["a", 1],["b", 2],]);map .delete ("a");console .log (map );
ts
constmap = newMap ([["a", 1],["b", 2],]);map .delete ("a");console .log (map );
delete
の戻り値は、キーが存在した場合true
、そうでない場合false
になります。
ts
constmap = newMap ([["a", 1]]);console .log (map .delete ("a"));console .log (map .delete ("b"));
ts
constmap = newMap ([["a", 1]]);console .log (map .delete ("a"));console .log (map .delete ("b"));
キーの有無を確認する - Map.prototype.has()
Map
にキーが存在するかどうかを調べるにはhas
メソッドを使います。
ts
constmap = newMap ([["a", 1]]);console .log (map .has ("a"));console .log (map .has ("b"));
ts
constmap = newMap ([["a", 1]]);console .log (map .has ("a"));console .log (map .has ("b"));
要素が存在するかをhas
チェックしてから、get
で要素を取得するコードはTypeScriptではうまく書けません。
ts
constmap = newMap ([["a", 1]]);if (map .has ("a")) {// TypeScriptは"a"があることを認識しないconstn =map .get ("a");Object is possibly 'undefined'.2532Object is possibly 'undefined'.* 2; n }
ts
constmap = newMap ([["a", 1]]);if (map .has ("a")) {// TypeScriptは"a"があることを認識しないconstn =map .get ("a");Object is possibly 'undefined'.2532Object is possibly 'undefined'.* 2; n }
この場合、get
で値を取得して、その値がundefined
でないことをチェックするとうまくいきます。
ts
constmap = newMap ([["a", 1]]);constn =map .get ("a");if (typeofn === "number") {n * 2;}
ts
constmap = newMap ([["a", 1]]);constn =map .get ("a");if (typeofn === "number") {n * 2;}
要素の個数を取得する - Map.prototype.size()
Map
に登録されている要素数を調べるにはsize
フィールドの値を見ます。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);console .log (map .size );
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);console .log (map .size );
全要素を削除する - Map.prototype.clear()
Map
に登録されている要素をすべて削除するにはclear
メソッドを使います。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);console .log (map .size );map .clear ();console .log (map .size );
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);console .log (map .size );map .clear ();console .log (map .size );
キーを列挙する - Map.prototype.keys()
keys
メソッドはキーの反復可能オブジェクトを返します。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constkeys = [...map .keys ()];console .log (keys );
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constkeys = [...map .keys ()];console .log (keys );
値を列挙する - Map.prototype.values()
values
メソッドは値の反復可能オブジェクトを返します。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constvalues = [...map .values ()];console .log (values );
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constvalues = [...map .values ()];console .log (values );
キーと値のペアを列挙する - Map.prototype.entries()
entries
メソッドはキーと値の反復可能オブジェクトを返します。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constkeyValues = [...map .entries ()];console .log (keyValues );
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constkeyValues = [...map .entries ()];console .log (keyValues );
キーと値のペアを反復する
Map
はfor...of
で反復できます。反復の順序は登録された順です。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);for (const [key ,value ] ofmap ) {console .log (key ,value );// "a", 1// "b", 2// "c", 3 の順で出力される}
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);for (const [key ,value ] ofmap ) {console .log (key ,value );// "a", 1// "b", 2// "c", 3 の順で出力される}
複製する
Map
オブジェクトを複製(シャローコピー)するには、MapオブジェクトをMapコンストラクタに渡します。
ts
constmap1 = newMap ([["a", 1]]);constmap2 = newMap (map1 );console .log (map2 );
ts
constmap1 = newMap ([["a", 1]]);constmap2 = newMap (map1 );console .log (map2 );
Mapは直接JSONにできない
Map
オブジェクトはJSON.stringifyにかけても、登録されている要素はJSONになりません。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);console .log (JSON .stringify (map ));
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);console .log (JSON .stringify (map ));
Map
をJSON化する場合は、一度オブジェクトにする必要があります。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constobj =Object .fromEntries (map );console .log (JSON .stringify (obj ));
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constobj =Object .fromEntries (map );console .log (JSON .stringify (obj ));
他の型との相互運用
Mapを配列にする
Map<K, V>
にスプレッド構文を使うと、タプル型配列[K, V][]
が得られます。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constkeyValues = [...map ];console .log (keyValues );
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constkeyValues = [...map ];console .log (keyValues );
オブジェクトをMapにする
オブジェクトをMap
に変換するには、Object.entries
の戻り値をMapコンストラクタに渡します。
ts
constobj = {a : 1,b : 2,c : 3 };constmap = newMap (Object .entries (obj ));console .log (map );
ts
constobj = {a : 1,b : 2,c : 3 };constmap = newMap (Object .entries (obj ));console .log (map );
Mapをオブジェクトにする
Mapをオブジェクトにするには、Object.fromEntries
にMapオブジェクトを渡します。
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constobj =Object .fromEntries (map );console .log (obj );
ts
constmap = newMap ([["a", 1],["b", 2],["c", 3],]);constobj =Object .fromEntries (map );console .log (obj );
Mapとオブジェクトの違い
キーと値のペアが表現ができるという点で、Map
とオブジェクトは似ていますが、次の違いがあります。
違い | Map | オブジェクト |
---|---|---|
プロトタイプキーの上書き | 起きない | 起こりうる |
キーに使える型 | 任意の型 | string かsymbol |
反復の順序 | 挿入順 | 複雑なロジック |
JSON化 | 直接できない | 直接できる |
プロトタイプキーの上書き
オブジェクトはプロトタイプのキーを上書きする可能性があります。
js
constobj = {};console .log (obj .toString );obj .toString = 1;console .log (obj .toString );
js
constobj = {};console .log (obj .toString );obj .toString = 1;console .log (obj .toString );
Map
は要素をセットしてもプロトタイプのキーを上書きする心配がありません。要素とプロトタイプは別の領域にあるためです。
ts
constmap = newMap <string, any>();console .log (map .toString );map .set ("toString", 1);console .log (map .toString );
ts
constmap = newMap <string, any>();console .log (map .toString );map .set ("toString", 1);console .log (map .toString );
キーに使える型
オブジェクトのキーに使える型はstring
型かsymbol
型のどちらです。Map
は任意の型をキーにできます。
反復の順序
オブジェクトのプロパティの反復順序は、書いた順や追加した順ではなく、複雑なロジックになっています。
📄️ オブジェクトをループする方法
JavaScript・TypeScriptでオブジェクトのプロパティをループする方法を説明します。
Map
の要素の反復順序は要素を追加した順であることが保証されています。
JSON化
オブジェクトはそのままJSON.stringify
でJSON化できます。Map
はJSON.stringify
しても要素はJSONになりません。一度Map
をオブジェクトに変換する必要があります。
Mapとオブジェクトの書き方比較
Map
とオブジェクトは似た操作ができます。次がその対応表です。
Map | オブジェクト | |
---|---|---|
型注釈の書き方 | Map<K, V> | Record<K, V> |
初期化 | new Map([["a", 1]]) | { a: 1 } |
要素のセット | map.set(key, value) | obj[key] = value |
値の取得 | map.get(key) | obj[key] |
要素の削除 | map.delete(key) | delete obj.key |
キーの有無確認 | map.has(key) | key in obj |
要素数の取得 | map.size | Object.keys(obj).length |
全要素削除 | map.clear() | - |
キーの列挙 | map.keys() | Object.keys(obj) |
値の列挙 | map.values() | Object.values(obj) |
要素の列挙 | map.entries() | Object.entries(obj) |
複製 | new Map(map) | { ...obj } |
📄️ Record<Keys, Type>
キー・バリューからオブジェクト型を作る
学びをシェアする
🗺Mapはキーと値のペアを扱うJSビルトインのAPI
📝TypeScriptではMap<string, number>のように型注釈する
🔬キーは厳密等価で判定される
🔪Mapは直接JSON化できない
⚖️Mapとオブジェクトの違い
→ Mapはキーに任意の型が使える
→ Mapはキーの順序が挿入順保証
『サバイバルTypeScript』より