İçeriğe geç
TypeScript

TypeScript Enum: Sabit Değerler Yönetimi

Tarık Tunç
TypeScript Enum: Sabit Değerler Yönetimi

TypeScript Enum: Sabit Değerler Yönetimi

Enum'lar (enumeration), ilişkili sabit değerleri mantıksal bir grup altında toplamanızı sağlayan TypeScript özelliğidir. Kod okunabilirliğini artırır, magic number ve magic string kullanımını ortadan kaldırır. Bu yazıda TypeScript enum'larını tüm yönleriyle inceleyeceğiz.

Numeric Enum

En temel enum türüdür. Varsayılan olarak 0'dan başlayan sayısal değerler atanır:

// Varsayılan numeric enum
enum Yon {
  Kuzey,  // 0
  Guney,  // 1
  Dogu,   // 2
  Bati    // 3
}

console.log(Yon.Kuzey); // 0
console.log(Yon[0]);     // "Kuzey" (reverse mapping)

// Başlangıç değeri belirleme
enum HttpDurum {
  OK = 200,
  Created = 201,
  BadRequest = 400,
  Unauthorized = 401,
  NotFound = 404,
  InternalServerError = 500
}

function durumKontrol(kod: HttpDurum): string {
  switch (kod) {
    case HttpDurum.OK:
      return "Başarılı";
    case HttpDurum.NotFound:
      return "Bulunamadı";
    case HttpDurum.InternalServerError:
      return "Sunucu Hatası";
    default:
      return "Bilinmeyen Durum";
  }
}

String Enum

String enum'lar, daha okunabilir ve debug edilebilir değerler sunar:

enum SiparisDurumu {
  Beklemede = "BEKLEMEDE",
  Hazirlaniyor = "HAZIRLANIYOR",
  Kargoda = "KARGODA",
  TeslimEdildi = "TESLIM_EDILDI",
  IptalEdildi = "IPTAL_EDILDI"
}

enum Renk {
  Kirmizi = "#FF0000",
  Yesil = "#00FF00",
  Mavi = "#0000FF",
  Siyah = "#000000",
  Beyaz = "#FFFFFF"
}

function durumMesaji(durum: SiparisDurumu): string {
  switch (durum) {
    case SiparisDurumu.Beklemede:
      return "Siparişiniz onay bekliyor.";
    case SiparisDurumu.Kargoda:
      return "Siparişiniz yola çıktı!";
    case SiparisDurumu.TeslimEdildi:
      return "Siparişiniz teslim edildi.";
    default:
      return "Durum güncelleniyor...";
  }
}
İpucu: String enum'lar, numeric enum'lardan farklı olarak reverse mapping desteklemez. Ancak hata ayıklama sırasında değerler doğrudan okunabilir olduğu için daha kullanışlıdır. API iletişiminde de string enum'lar tercih edilir.

const enum

const enum, derleme zamanında inline edilir ve üretilen JavaScript'te enum objesi oluşturulmaz:

const enum Islem {
  Topla = "TOPLA",
  Cikar = "CIKAR",
  Carp = "CARP",
  Bol = "BOL"
}

// Derleme sonrası: const sonuc = "TOPLA"
const sonuc = Islem.Topla;

// Karşılaştırma
// Normal enum - runtime'da obje oluşturur
enum NormalYon {
  Kuzey = "KUZEY",
  Guney = "GUNEY"
}

// const enum - inline edilir, obje oluşturmaz
const enum ConstYon {
  Kuzey = "KUZEY",
  Guney = "GUNEY"
}

// const enum ile reverse mapping yapılamaz
// ConstYon["KUZEY"] // HATA!
Uyarı: const enum kullanırken dikkatli olun. Eğer kütüphane geliştiriyorsanız, tüketiciler isolatedModules flag'i kullanıyorsa sorun yaşayabilir. Bu durumda normal enum veya union type tercih edin.

Enum Alternatifleri

Modern TypeScript'te enum'ların bazı dezavantajları nedeniyle alternatifler de yaygın kullanılır:

// Alternatif 1: Union Type (Önerilen)
type SiparisDurumu = "beklemede" | "hazirlaniyor" | "kargoda" | "teslim_edildi";

function durumKontrol(durum: SiparisDurumu): boolean {
  return durum === "teslim_edildi";
}

// Alternatif 2: as const ile obje
const HTTP_DURUM = {
  OK: 200,
  NotFound: 404,
  ServerError: 500
} as const;

type HttpDurumDeger = typeof HTTP_DURUM[keyof typeof HTTP_DURUM];
// 200 | 404 | 500

function istek(durum: HttpDurumDeger): void {
  if (durum === HTTP_DURUM.OK) {
    console.log("Başarılı!");
  }
}

// Alternatif 3: const object + helper
const Renkler = {
  Kirmizi: "#FF0000",
  Yesil: "#00FF00",
  Mavi: "#0000FF"
} as const;

type RenkAdi = keyof typeof Renkler;         // "Kirmizi" | "Yesil" | "Mavi"
type RenkDeger = typeof Renkler[RenkAdi];     // "#FF0000" | "#00FF00" | "#0000FF"

Enum ve Type Guard

enum KullaniciTipi {
  Admin = "ADMIN",
  Editor = "EDITOR",
  Okuyucu = "OKUYUCU"
}

interface AdminKullanici {
  tip: KullaniciTipi.Admin;
  isim: string;
  superYetki: boolean;
}

interface EditorKullanici {
  tip: KullaniciTipi.Editor;
  isim: string;
  kategoriler: string[];
}

interface OkuyucuKullanici {
  tip: KullaniciTipi.Okuyucu;
  isim: string;
}

type Kullanici = AdminKullanici | EditorKullanici | OkuyucuKullanici;

function kullaniciIsle(kullanici: Kullanici): void {
  switch (kullanici.tip) {
    case KullaniciTipi.Admin:
      console.log(`Admin: ${kullanici.isim}, Super: ${kullanici.superYetki}`);
      break;
    case KullaniciTipi.Editor:
      console.log(`Editör: ${kullanici.isim}, Kategoriler: ${kullanici.kategoriler}`);
      break;
    case KullaniciTipi.Okuyucu:
      console.log(`Okuyucu: ${kullanici.isim}`);
      break;
  }
}
Bilgi: Enum vs Union Type tartışması TypeScript topluluğunda hâlâ devam etmektedir. Genel kural: basit durumlarda union type, runtime'da değerlere erişim gerekiyorsa enum veya as const object kullanın. React projelerinde union type ve as const yaklaşımı daha yaygındır.

Sonuç

TypeScript enum'ları, sabit değerleri organize etmenin güçlü bir yoludur. Numeric enum, string enum ve const enum arasındaki farkları anlamak, doğru seçimi yapmanızı sağlar. Modern TypeScript'te union type ve as const alternatifleri de değerlendirilmelidir. Projenizin ihtiyaçlarına göre en uygun yaklaşımı seçin.

Kaynaklar

İlgili Yazılar