Enum adalah sekumpulan konstanta bernama yang dibuat dengan kata kunci enum. Daripada menulis angka atau teks yang gampang salah ketik di mana-mana, tiap pilihan diberi nama: Status.Active, Status.Pending. Mirip tombol kipas angin: di tombolnya tertulis Mati, Pelan, Kencang, tapi di dalam mesinnya yang dipakai angka 0, 1, 2.
🧪 Tebakan cepat: di
enum Status { Active, Inactive, Pending }, berapa nilaiStatus.Active? Dan setelah di-compile, objectStatuspunya berapa kunci: 3 atau 6? Tebak dulu, jawabannya ada di bagian "Numeric enum dan reverse mapping".
Numeric enum dan reverse mapping
enum Status {
Active, // 0
Inactive, // 1
Pending, // 2
}
console.log(Status.Active); // 0
console.log(Status[0]); // Active
Kalau gak diberi nilai, anggota enum dinomori otomatis mulai dari 0. Jadi Status.Active bernilai 0, dan di enum Warna { Merah, Hijau, Biru } nilai Warna.Merah juga 0. Kalau anggota pertama diberi angka, sisanya melanjutkan: enum Level { Rendah = 1, Sedang, Tinggi } membuat Level.Tinggi bernilai 3.
Beda dengan type, enum gak hilang saat compile. Ini JavaScript yang ditulis tsc untuk Status:
var Status;
(function (Status) {
Status[Status["Active"] = 0] = "Active";
Status[Status["Inactive"] = 1] = "Inactive";
Status[Status["Pending"] = 2] = "Pending";
})(Status || (Status = {}));
Status["Active"] = 0mengisi kunciActivedengan 0, dan hasilnya (0) dipakai lagi sebagai kunci:Status[0] = "Active".- Jadi tiap anggota punya dua arah: nama ke angka, dan angka ke nama. Arah angka ke nama disebut reverse mapping.
Object.keys(Status)menghasilkan["0", "1", "2", "Active", "Inactive", "Pending"]: 6 kunci, bukan 3. Itu jawaban tebakannya.
String enum
enum Status {
Active = "active",
Inactive = "inactive",
Pending = "pending",
}
console.log(Status.Active); // active
- Di string enum, tiap anggota wajib diberi nilai teks sendiri.
- Gak ada reverse mapping:
Object.keys(Status)cuma["Active", "Inactive", "Pending"]. - Keuntungannya, lebih mudah dibaca: saat debugging, log dan data API berisi
"active", bukan angka0yang harus kamu cocokkan sendiri.
Tapi enum itu ketat. Parameter bertipe Status gak menerima teks biasa, walau isinya sama persis:
getStatusLabel("active");
error TS2345: Argument of type '"active"' is not assignable to parameter of type 'Status'.
Kamu wajib menulis getStatusLabel(Status.Active).
Union literal dan object as const
Yang sering dipakai sebagai ganti enum adalah union literal (sudah kamu kenal):
type Status = "active" | "inactive" | "pending";
function getStatusLabel(status: Status): string {
if (status === "active") return "Aktif";
if (status === "inactive") return "Nonaktif";
return "Menunggu";
}
getStatusLabel("active"); // "Aktif"
getStatusLabel("selesai"); // error
error TS2345: Argument of type '"selesai"' is not assignable to parameter of type 'Status'.
Teks yang benar langsung diterima, teks yang salah ditolak. Setelah compile, type Status hilang total: 0 baris JavaScript.
Butuh daftarnya juga saat program jalan, misalnya untuk mengisi dropdown? Pakai object biasa dengan as const:
const STATUS = {
Active: "active",
Inactive: "inactive",
Pending: "pending",
} as const;
type Status = (typeof STATUS)[keyof typeof STATUS]; // "active" | "inactive" | "pending"
as constmemberi tahu TypeScript bahwa object ini gak akan berubah: tiap nilai jadi tipe teks persisnya ("active", bukanstring) dan semuanyareadonly.typeof STATUSmengambil tipe object-nya,keyofmengambil nama kuncinya, dan[...]mengambil tipe nilainya.- JavaScript-nya tetap object biasa, tanpa reverse mapping.
Kenapa banyak tim memilih union
Hampir semua fitur TypeScript cuma tipe yang dihapus saat compile. Enum termasuk sedikit fitur yang menghasilkan kode JavaScript sendiri. Akibatnya:
- Node.js versi baru bisa menjalankan file
.tslangsung dengan cara menghapus tipenya. Enum gak bisa sekadar dihapus, jadi Node berhenti:SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode. - Opsi tsconfig
erasableSyntaxOnly(TypeScript 5.8 ke atas) melarang semua sintaks seperti itu. Dengan opsi ini, tiapenumditolak:This syntax is not allowed when 'erasableSyntaxOnly' is enabled.(ts(1294)). Union dan objectas consttetap lolos.
Enum tetap sah dan masih banyak dipakai di proyek lama. Untuk kode baru, union literal biasanya cukup, dan object as const kalau daftarnya juga dibutuhkan saat jalan.
⚠️ Jebakan yang sering ketemu
- Numeric enum untuk data berupa teks. Data dari API berisi
"active", sedangkanStatus.Activebernilai 0, jadistatus === Status.Activeselalufalse. Kalau datanya teks, pakai string enum atau union. - Mengirim teks biasa ke parameter enum.
getStatusLabel("active")ditolak kalau parameternya string enum. TulisStatus.Active, atau pakai union. - Lupa memberi nilai di string enum. Begitu satu anggota diberi teks, anggota sesudahnya juga wajib diberi nilai.
- Label ketiga meleset.
"pending"artinya masih menunggu, jadi labelnya"Menunggu", bukan penolakan seperti "Ditolak".
TL;DR: enum membuat konstanta bernama. Numeric enum dinomori dari 0 (Status.Active = 0, Warna.Merah = 0) dan menghasilkan object dengan reverse mapping (Status[0] = "Active", total 6 kunci). String enum memberi tiap anggota teks sendiri, jadi lebih mudah dibaca, tapi gak menerima teks biasa. Union literal seperti type Status = "active" | "inactive" | "pending" hilang total saat compile dan menerima teks yang benar, dan object as const dipakai kalau daftarnya juga butuh saat jalan. Banyak tim memilih union karena enum ditolak erasableSyntaxOnly dan gak bisa dijalankan Node secara langsung.