Bayangkan kamu sedang membaca kode dan menemukan baris seperti if (order.status === 2). Angka 2 itu artinya apa? “Sudah dikirim”? “Dibatalkan”? “Menunggu pembayaran”? Tidak ada yang tahu kecuali kamu rela menelusuri seluruh isi file. Angka dan string lepas yang berserakan di kode itu sumber bug yang diam-diam, karena nilai-nilai itu tidak membawa makna apa pun sendirian.
Enum adalah jawaban TypeScript untuk masalah tersebut. Sebuah enum (singkatan dari “enumeration”) adalah kumpulan konstanta terkait yang diberi nama. Daripada menulis 2, kamu menulis OrderStatus.Shipped, dan tiba-tiba kode itu terbaca seperti kalimat. Di panduan ini kita akan mengupas apa itu enum, melihat dua jenis yang disediakan TypeScript (angka dan string), berbicara jujur soal kapan enum membantu, lalu membandingkannya dengan alternatif yang populer: union dari string literal. Di akhir, kamu tidak cuma tahu cara menulis enum, tapi juga kapan sebaiknya memakainya dan kapan lebih baik tidak.
Apa itu enum sebenarnya
Pada bentuk paling sederhana, enum adalah cara memberi nama ramah untuk sekelompok nilai yang tetap. Bayangkan empat arah mata angin pada kompas. Jumlahnya pas empat, tidak pernah berubah, dan masing-masing pantas punya nama yang jelas. Ini contoh yang pas banget untuk enum.
enum Direction {
Up,
Down,
Left,
Right,
}
const move: Direction = Direction.Up;
Di sini Direction adalah enum-nya, sementara Up, Down, Left, dan Right adalah anggotanya. Tiap anggota merupakan satu konstanta bernama. Saat kamu mengetik Direction. di editor, autocomplete langsung menampilkan daftar lengkapnya, jadi kamu tidak mungkin tidak sengaja memasukkan nilai yang bukan bagian dari daftar itu.
Inti idenya adalah himpunan ini tertutup. Sebuah arah pasti salah satu dari empat tadi, tidak ada yang lain. Enum paling bersinar justru ketika sebuah nilai adalah “salah satu dari daftar pilihan yang kecil dan tetap.”
Kenapa tidak pakai string atau angka biasa saja?
Nilai biasa memang bisa dipakai, tapi tidak memberi jaring pengaman. Kalau kamu salah ketik "shippd", TypeScript dengan santai menerimanya sebagai string. Enum memaksa setiap nilai berasal dari daftar yang sudah disetujui, sehingga salah ketik berubah menjadi error saat kompilasi, bukan kejutan saat program berjalan.
Enum angka
Secara bawaan, enum di TypeScript bertipe angka. Kalau kamu tidak menetapkan nilai sendiri, anggotanya akan mendapat angka otomatis, dimulai dari 0 dan naik terus.
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right, // 3
}
console.log(Direction.Left); // 2
Kamu juga bisa menentukan angka awal, dan sisanya akan melanjutkan dari situ:
enum StatusCode {
Ok = 200,
Created = 201,
// anggota berikutnya tetap perlu nilai eksplisit di sini,
// karena 202, 203... adalah kode HTTP yang punya arti
Accepted = 202,
}
Enum angka punya satu keunikan yang perlu kamu tahu: ia bisa dipetakan balik (reverse mapping). TypeScript mengizinkan kamu berangkat dari angka kembali ke namanya.
enum Direction { Up, Down, Left, Right }
console.log(Direction[0]); // "Up"
console.log(Direction.Up); // 0
Itu kadang berguna, tapi artinya enum angka dikompilasi menjadi objek yang sedikit lebih besar saat program berjalan. Yang lebih penting, nilai dasarnya hanyalah angka, dan ini membawa satu jebakan nyata.
Enum angka menerima angka apa saja
Pada enum angka biasa, TypeScript membolehkan kamu memberikan sembarang angka ke tipe enum tersebut, bahkan angka yang bukan anggotanya. Menulis let d: Direction = 99 tidak memunculkan error secara bawaan. Angka 99 bukan Up, Down, Left, maupun Right, tetapi tetap lolos. Inilah sumber kebingungan yang umum dan alasan besar kenapa banyak tim lebih memilih enum string.
Enum string
Enum string adalah enum yang setiap anggotanya kamu beri nilai string secara eksplisit. Tidak ada penomoran otomatis, jadi kamu harus menulis tiap nilainya, tapi imbalannya sepadan: nilai saat program berjalan jadi mudah dibaca.
enum OrderStatus {
Pending = "PENDING",
Paid = "PAID",
Shipped = "SHIPPED",
Cancelled = "CANCELLED",
}
const status: OrderStatus = OrderStatus.Shipped;
console.log(status); // "SHIPPED"
Bandingkan dengan enum angka. Kalau kamu mencetak enum angka, yang muncul adalah 2, yang tidak berarti apa-apa bagi manusia yang membaca log server atau debugger. Cetak enum string, yang muncul adalah "SHIPPED". Saat ada yang rusak jam dua dini hari, perbedaan itu sangat terasa.
Enum string juga tidak punya pemetaan balik, dan tidak diam-diam menerima nilai sembarangan seperti enum angka. Untuk sebagian besar kode aplikasi, enum string adalah pilihan bawaan yang lebih aman dan lebih jelas.
Berikut contoh kecil tapi realistis. Misalkan kamu memodelkan akun pengguna di ACY Partner Indonesia:
enum UserRole {
Admin = "ADMIN",
Editor = "EDITOR",
Viewer = "VIEWER",
}
interface User {
name: string;
email: string;
role: UserRole;
}
const jane: User = {
name: "Jane Doe",
email: "jane@example.com",
role: UserRole.Editor,
};
function canPublish(user: User): boolean {
return user.role === UserRole.Admin || user.role === UserRole.Editor;
}
Perhatikan betapa canPublish terbaca hampir seperti bahasa sehari-hari. Tidak ada yang perlu mengingat bahwa “editor” itu peran nomor 1. Namanya yang membawa makna.
Kapan enum benar-benar membantu keterbacaan
Enum bukan sihir, dan tidak gratis. Enum baru terasa sepadan dalam situasi tertentu:
- Himpunannya tetap dan bermakna. Status pesanan, peran pengguna, hari dalam seminggu, warna lampu lalu lintas. Ini daftar yang stabil dan tiap isinya pantas punya nama.
- Nilainya muncul di banyak tempat. Kalau
UserRole.Adminmuncul di belasan file, satu definisi enum menjaga semuanya konsisten dan memberi satu titik untuk diubah. - Kamu mau autocomplete dan pengelompokan. Mengetik
UserRole.lalu melihat seluruh daftarnya adalah keuntungan produktivitas yang nyata, sekaligus mendokumentasikan pilihan yang ada untuk developer berikutnya.
Berikut perbandingan sebelum-sesudah supaya soal keterbacaan jadi konkret.
// Sebelum: angka ajaib, tanpa makna
function describe(status: number): string {
if (status === 0) return "Menunggu";
if (status === 1) return "Aktif";
if (status === 2) return "Ditutup";
return "Tidak diketahui";
}
// Sesudah: maksudnya langsung terbaca dari nama
enum AccountStatus {
Waiting = "WAITING",
Active = "ACTIVE",
Closed = "CLOSED",
}
function describe(status: AccountStatus): string {
switch (status) {
case AccountStatus.Waiting: return "Menunggu";
case AccountStatus.Active: return "Aktif";
case AccountStatus.Closed: return "Ditutup";
}
}
Versi kedua lebih sulit disalahgunakan dan lebih gampang dibaca beberapa bulan kemudian. Itulah inti penjualan enum.
Alternatif yang umum: union dari string literal
Ini sering bikin pemula kaget: sering kali kamu sebenarnya tidak butuh enum sama sekali. TypeScript bisa menyatakan “salah satu dari sekumpulan string yang tetap” lewat union dari string literal biasa.
type OrderStatus = "PENDING" | "PAID" | "SHIPPED" | "CANCELLED";
const status: OrderStatus = "SHIPPED"; // boleh
const broken: OrderStatus = "shipped"; // error: tidak ada di himpunan
Ini hampir melakukan semua yang dilakukan enum string. Kamu tetap dapat autocomplete, tetap dapat error saat kompilasi untuk nilai yang salah, dan nilai saat program berjalan tetaplah string yang mudah dibaca. Perbedaan besarnya: tipe union literal menghilang saat program berjalan — ia murni informasi tipe, jadi tidak menambah kode apa pun pada JavaScript hasil kompilasi. Enum, sebaliknya, menghasilkan objek nyata yang tetap ada saat program berjalan.
Lalu bagaimana memilihnya? Ini perbandingan yang jujur.
| Aspek | Enum string | Union string literal |
|---|---|---|
| Keamanan saat kompilasi | Ya | Ya |
| Autocomplete | Ya | Ya |
| Nilai runtime mudah dibaca | Ya | Ya (hanya string) |
| Menambah kode runtime | Ya (sebuah objek) | Tidak (terhapus) |
| Iterasi semua nilai | Mudah (Object.values) |
Perlu array manual |
Akses bernamespace (X.Member) |
Ya | Tidak (pakai string mentah) |
| Cocok dengan data JS biasa | Perlu pemetaan | String langsung cocok |
Union literal cenderung unggul ketika kamu berurusan dengan data yang memang datang sebagai string biasa — misalnya respons JSON dari sebuah API. Field status kamu sudah berupa "SHIPPED", jadi tipe union pas banget tanpa langkah konversi. Enum bisa terasa seperti basa-basi tambahan di situ.
Enum cenderung unggul ketika kamu ingin satu rumah bernama untuk nilai-nilainya, iterasi mudah atas tiap anggota, serta kemampuan menulis UserRole.Admin alih-alih mengulang string mentah di mana-mana.
Pilihan bawaan yang praktis
Kalau ragu, mulailah dengan union string literal. Lebih ringan, memetakan rapi ke data JSON, dan kamu selalu bisa menaikkannya menjadi enum nanti kalau ternyata butuh iterasi atau namespace bersama. Banyak basis kode TypeScript baik-baik saja tanpa satu pun enum.
Sedikit soal const enum dan jebakan lain
Kamu mungkin menemui const enum, yang menyuruh TypeScript menyisipkan nilainya langsung dan melewati pembuatan objek runtime. Kedengarannya bagus untuk performa, tapi ia berinteraksi buruk dengan beberapa pengaturan build dan kompiler mode modul terisolasi, serta bisa memunculkan error membingungkan saat kode tersebar di banyak file. Untuk kebanyakan proyek, pilihan yang lebih sederhana dan lebih portabel adalah enum string biasa atau, lebih sering, union literal. Tetap konseptual di sini: kalau kamu tidak secara khusus butuh penyisipan nilai, kemungkinan besar kamu tidak butuh const enum.
Pelajaran yang lebih luas: enum itu alat, bukan tujuan. Pakai ketika himpunan yang tetap dan bernama benar-benar membuat kodemu lebih jelas, dan jangan sungkan melewatkannya kalau union literal sudah cukup dengan beban yang lebih ringan.
Rangkuman
Enum memberi nama pada sekumpulan konstanta terkait yang tetap, supaya kodemu berhenti bergantung pada angka misterius dan string lepas. Ini yang perlu kamu bawa pulang:
- Enum adalah himpunan nilai bernama yang tertutup, seperti
Direction.UpatauOrderStatus.Shipped. - Enum angka adalah bawaan; anggotanya bernomor otomatis dari
0. Ia mendukung pemetaan balik tapi menerima angka sembarang, yang merupakan celah keamanan. - Enum string memberi tiap anggota nilai string eksplisit. Ia mudah dibaca di log, lebih aman, dan jadi pilihan harian yang lebih baik di antara keduanya.
- Enum membantu keterbacaan ketika himpunannya tetap, bermakna, dipakai di banyak tempat, dan kamu mau autocomplete plus satu sumber kebenaran.
- Union string literal adalah alternatif umum yang ringan. Ia memberi keamanan kompilasi yang sama, terhapus saat runtime, dan memetakan sempurna ke string JSON biasa — tapi kehilangan iterasi mudah dan akses bernamespace.
Tidak ada satu jawaban yang mutlak benar. Pilih alat yang membuat orang berikutnya yang membaca kodemu langsung mengangguk paham. Sering kali itu enum string; cukup sering juga, itu cuma union literal.