Menu

Dictionary TypeScript: Index Signature, Record, dan Map

TypeScript tidak punya class dictionary atau hashmap; kamu memberi tipe pada lookup key-value dengan index signature, Record<K, V>, atau Map<K, V>. Pelajari masing-masing, cara memeriksa apakah sebuah key ada, menambah, menghapus, dan mengiterasi, serta kenapa noUncheckedIndexedAccess penting untuk dictionary.

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

TypeScript tidak punya class dictionary atau hashmap tersendiri. Dictionary adalah objek biasa yang diberi tipe dengan index signature, { [key: string]: number }, tipe yang sama yang ditulis Record<string, number>, atau Map<string, number>. Ketiganya menyimpan nilai berdasarkan key; perbedaannya ada pada tipe key, cara key yang tidak ada diberi tipe, dan cara diserialisasi.

Untuk key berupa string dan data berbentuk JSON, objek dengan Record<string, T> adalah pilihan yang biasa. Untuk key yang bukan string, atau entri yang terus-menerus ditambah dan dihapus, pakai Map.

Index Signature

Index signature, [key: KeyType]: ValueType, berarti "setiap key dengan tipe ini dipetakan ke nilai dengan tipe ini". Nama key-nya (key, name, userId) hanya dokumentasi. Tipe key bisa berupa string, number, symbol, pola template literal, atau union dari semuanya.

Key berupa angka diubah menjadi string oleh JavaScript, jadi objek { [id: number]: string } tetap punya key string saat runtime: Object.keys({ 1: "one" }) adalah [ '1' ]. Index signature number hanya membatasi cara kamu mengaksesnya di TypeScript.

Record<K, V>

Record<string, V> adalah singkatan dari { [key: string]: V }. Dengan union dari key literal sebagai pengganti string, tipe ini menjadi dictionary tetap yang wajib berisi setiap key:

Menghilangkan staging dari urls menghasilkan error kompilasi TS2741 (Property 'staging' is missing...), yang membuat Record dengan key union menjadi tabel lookup yang diperiksa. Partial membuat setiap nilai bertipe number | undefined.

Map sebagai Hash Map

Map menerima key dengan tipe apa pun, menjaga urutan penyisipan, punya size, dan memberi tipe pada key yang tidak ada dengan jujur: get mengembalikan V | undefined.

Memeriksa Apakah Sebuah Key Ada

Ada beberapa cara memeriksa, dan artinya tidak semuanya sama:

PemeriksaanBerlaku untukHati-hati dengan
Object.hasOwn(obj, key)objekES2022; pakai Object.prototype.hasOwnProperty.call(obj, key) untuk target yang lebih lama
key in objobjekJuga true untuk key warisan seperti toString dan constructor
obj[key] !== undefinedobjekTidak bisa membedakan key yang tidak ada dengan key yang disimpan sebagai undefined
if (obj[key])objekJuga false untuk nilai 0, "", dan false
map.has(key)MapTidak mempersempit map.get(key) setelahnya
map.get(key) !== undefinedMapCatatan undefined yang sama seperti pada objek

Masalah key warisan inilah alasan key dari pengguna seperti "constructor" atau "__proto__" membuat objek biasa berisiko dipakai sebagai dictionary. Map tidak punya key semacam itu.

Masalah Tipe untuk Key yang Tidak Ada

Pada index signature atau Record<string, T>, membaca key apa pun bertipe T, bahkan key yang tidak ada. Compiler membiarkanmu memanggil method pada nilai yang saat runtime bernilai undefined:

Opsi compiler noUncheckedIndexedAccess memperbaiki hal ini: dengan opsi itu, colors["grass"] bertipe string | undefined dan pemanggilan toUpperCase menjadi error kompilasi sampai kamu memeriksanya. Opsi ini bukan bagian dari strict, jadi harus dinyalakan secara terpisah di tsconfig.json; lihat strict mode untuk flag lain di sekitarnya. Map tidak punya celah ini, karena get selalu menyertakan undefined.

Menambah, Menghapus, dan Mengiterasi

delete bisa dipakai pada property index signature. Pada property bernama yang wajib di sebuah object type, itu menghasilkan error kompilasi TS2790, The operand of a 'delete' operator must be optional.

Mana yang Dipakai

KebutuhanPakai
Key berupa string, JSON masuk atau keluarRecord<string, T>
Kumpulan key yang tetap dan diketahui, semuanya wajibRecord<"a" | "b", T>
Property bernama ditambah key tambahan sembarangobject type dengan index signature
Key berupa objek, angka yang tetap disimpan sebagai angka, atau apa pun yang bukan stringMap<K, V>
Sering ditambah dan dihapus, atau ukurannya sering dibacaMap<K, V>
Key yang berasal dari penggunaMap<K, V> (tanpa key warisan)

Pertanyaan yang sering diajukan

Bagaimana cara membuat dictionary di TypeScript?

Beri tipe pada objek biasa dengan index signature, const ages: { [name: string]: number } = {}, atau yang setara, Record<string, number>. Lalu tambahkan entri dengan ages["ada"] = 36. Untuk key yang bukan string, atau koleksi yang sering ditambah dan dihapus isinya, pakai new Map<string, number>().

Apakah TypeScript punya HashMap?

Tidak dengan nama itu. Map bawaan JavaScript adalah hash map: Map<K, V> menyimpan pasangan key-value dengan pencarian cepat berdasarkan key, menjaga urutan penyisipan, dan menerima tipe key apa pun. Objek biasa bertipe Record<string, V> adalah pilihan umum lainnya untuk key berupa string.

Bagaimana cara memeriksa apakah sebuah key ada di dictionary TypeScript?

Untuk dictionary berupa objek, pakai Object.hasOwn(dict, key) atau key in dict (yang juga melihat property warisan seperti toString), atau baca nilainya lalu bandingkan dengan undefined. Untuk Map, pakai map.has(key), atau periksa hasil map.get(key) secara langsung, karena has tidak mempersempit get yang dipanggil setelahnya.

Apa bedanya index signature dan Record?

{ [key: string]: T } dan Record<string, T> mendeskripsikan tipe yang sama. Record lebih pendek dan juga bisa menerima union dari key tertentu, Record<"a" | "b", T>, yang mewajibkan setiap key ada. Index signature bisa digabung dengan property bernama dalam satu object type, dan key-nya bisa diberi nama yang menjelaskannya, seperti { [userId: string]: User }.

Kenapa membaca key dictionary yang tidak ada tidak menghasilkan error?

Secara default, dict[key] pada index signature atau Record<string, T> bertipe T, meskipun nilainya undefined untuk key yang tidak ada saat runtime. Nyalakan noUncheckedIndexedAccess di tsconfig.json dan tipenya menjadi T | undefined, sehingga kamu wajib memeriksanya. strict tidak mencakup opsi ini.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai