Menu

Map di TypeScript: Map<K, V>, get, set, has, dan Iterasi

Cara memakai Map di TypeScript: membuat Map<K, V> yang bertipe, kenapa get mengembalikan V | undefined, set, has, dan delete, iterasi sesuai urutan penyisipan, key berupa object, konversi dari dan ke object serta JSON, Map vs object vs Record, dan memberi tipe pada array.map().

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Map di TypeScript adalah Map bawaan JavaScript dengan key dan value yang bertipe: Map<string, number> memetakan string ke angka. Buat dengan new Map<K, V>(), lalu pakai set, get, has, dan delete. get mengembalikan V | undefined, karena key-nya bisa saja tidak ada.

Argumen tipe itulah yang membuat Map berguna di TypeScript: setiap set diperiksa, dan setiap get mengembalikan tipe value. Baris terakhir adalah error kompilasi (TS2345); @ts-expect-error membuat blok ini tetap bisa dijalankan.

Halaman ini membahas koleksi Map. Kalau kamu sedang mencari array.map(), materinya ada di bagian terakhir.

Membuat Map

Tipenya berasal dari argumen tipe, dari entri awal, atau dari anotasi. Entri awal berupa array berisi tuple [key, value], atau apa pun yang menghasilkan tuple seperti itu.

Ada dua jebakan inferensi:

  • new Map() tanpa argumen tipe dan tanpa entri bertipe Map<any, any>. Apa pun yang kamu masukkan atau ambil tidak diperiksa. Selalu tulis new Map<K, V>().
  • Entri dengan tipe value yang berbeda tidak disimpulkan menjadi union. new Map([["a", 1], ["b", "x"]]) adalah error TS2769 (No overload matches this call). Tulis tipenya: new Map<string, number | string>([...]).

get Mengembalikan V | undefined

Map tidak bisa menjanjikan bahwa sebuah key ada, jadi get bertipe V | undefined. Dengan strict, kamu harus menangani undefined sebelum memakai nilainya sebagai V:

index.ts(4,7): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.

Cara memperbaikinya, dari yang paling umum sampai yang paling jarang:

TypeScript tidak ingat bahwa has mengembalikan true saat kamu memanggil get sesudahnya. Memeriksa hasil get secara langsung lebih ringkas sekaligus aman. Non-null assertion, stock.get("apples")!, memang menghilangkan error-nya, tetapi tidak memberi perlindungan apa pun kalau key-nya tidak ada.

Method Map dan Tipenya

MemberTipe pada Map<K, V>Catatan
new Map<K, V>(entries?)Map<K, V>entries: iterable berisi [K, V]
set(key, value)thisMenambah atau mengganti; bisa dirangkai
get(key)V | undefinedundefined kalau tidak ada
has(key)boolean
delete(key)booleantrue kalau ada yang dihapus
clear()voidMenghapus semuanya
sizenumberProperti, bukan method
keys(), values()iterator berisi K, VSpread ke dalam array: [...map.keys()]
entries(), for...ofiterator berisi [K, V]Sesuai urutan penyisipan
forEach((value, key) => ...)voidPerhatikan: value ada di urutan pertama

Iterasi Map

Map diiterasi sesuai urutan penyisipan. for...of pada map menghasilkan tuple [key, value], bertipe [K, V].

Mengatur key yang sudah ada akan memperbarui value-nya tetapi mempertahankan posisi awalnya dalam urutan.

Key Berupa Object dan Menghitung

Nilai apa pun bisa menjadi key, termasuk object dan array. Key dibandingkan seperti ===: dua object dengan isi yang sama adalah key yang berbeda. Map juga merupakan cara standar untuk menghitung atau mengelompokkan item.

Untuk membuat key berdasarkan isi object, turunkan key berupa string atau angka, seperti user.id atau `${x},${y}`.

Map vs Object vs Record

Map<K, V>Object / Record<string, V>
Tipe keyapa saja, dibandingkan seperti ===string (angka menjadi string), symbol
Tipe untuk key yang tidak adaget mengembalikan V | undefinedobj[key] bertipe V kecuali noUncheckedIndexedAccess aktif
Urutanurutan penyisipansebagian besar urutan penyisipan, tetapi key yang mirip bilangan bulat didahulukan dengan urutan naik
Ukuranmap.sizeObject.keys(obj).length
Sering menambah dan menghapusdioptimalkan untuk itutidak dioptimalkan untuk itu
JSONtidak langsung (JSON.stringify(map) menghasilkan "{}")langsung
Sintaks literal, destructuringtidakya
Key warisan yang tidak disengajatidak ada"toString" in {} bernilai true

Aturan praktisnya: Map untuk koleksi yang key-nya adalah data (id user, kata, entri cache) dan berubah saat runtime; tipe object atau Record untuk sekumpulan key tetap yang sudah diketahui, dan untuk apa pun yang dikirim ke atau diterima dari JSON. Halaman dictionary membandingkan index signature, Record, dan Map untuk lookup dengan key berupa string.

Mengubah Map menjadi Object dan JSON

Entri Map bukan properti, jadi JSON.stringify tidak melihatnya. Konversi lewat Object.fromEntries dan Object.entries:

JSON.parse mengembalikan any, jadi as Record<...> menyatakan bentuk data yang diharapkan. Itu bukan pemeriksaan saat runtime; validasi JSON yang tidak tepercaya sebelum memercayai tipe tersebut.

Memberi Tipe pada array.map()

Banyak pencarian "typescript map" sebenarnya mencari method array, yang mengubah setiap elemen dan mengembalikan array baru. Tipenya disimpulkan dari callback, jadi anotasi jarang dibutuhkan:

Memberi anotasi pada tipe kembalian callback ((u): Option => ...) adalah cara paling jelas untuk menyatakan tipe hasilnya: properti yang hilang atau salah ketik di object yang dikembalikan lalu menjadi error kompilasi di callback tersebut.

Pertanyaan yang sering diajukan

Bagaimana cara membuat Map di TypeScript?

Kirim tipe key dan value ke constructor: const ages = new Map<string, number>(). Dengan entri awal, tipenya disimpulkan: new Map([["ada", 36]]) adalah Map<string, number>. new Map() polos tanpa tipe dan tanpa entri bertipe Map<any, any>, yang mematikan pemeriksaan, jadi selalu beri tipe.

Kenapa Map.get bisa mengembalikan undefined di TypeScript?

map.get(key) bertipe V | undefined karena key-nya mungkin tidak ada. TypeScript tidak menghubungkan map.has(key) sebelumnya dengan get sesudahnya, jadi bahkan setelah has kamu tetap perlu menangani undefined: simpan hasilnya lalu periksa, atau pakai nilai default dengan ??.

Apa perbedaan Map dan object di TypeScript?

Map menerima key bertipe apa pun (termasuk object), mempertahankan urutan penyisipan, punya size, dan dirancang untuk sering menambah dan menghapus. Object biasa atau Record<string, V> hanya punya key berupa string (dan symbol), bisa langsung diserialisasi ke JSON, serta mendukung sintaks literal dan destructuring. Pakai Map untuk koleksi ber-key yang dinamis, dan object untuk bentuk yang tetap serta data JSON.

Bagaimana cara mengubah Map menjadi object atau JSON di TypeScript?

Object.fromEntries(map) mengubah Map<string, V> menjadi object biasa, yang lalu bisa diserialisasi oleh JSON.stringify. JSON.stringify(map) langsung pada Map menghasilkan "{}", karena entri Map bukan properti. Kebalikannya adalah new Map(Object.entries(obj)).

Bagaimana cara memberi tipe pada callback array.map di TypeScript?

Biasanya tidak perlu: items.map((item) => item.name) menyimpulkan item dari array dan tipe hasilnya dari apa yang dikembalikan callback. Untuk memaksakan tipe hasil, kirim sebagai argumen tipe, items.map<string>(...), atau beri anotasi pada tipe kembalian callback-nya.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai