TypeScript enum, bir grup adlandırılmış sabiti tek bir isim altında toplar. Sayısal enum'larda üyeler 0'dan başlayarak otomatik artar ve ters eşleme (değerden isme) üretilir; string enum'larda her üyeye bir metin değeri yazarsınız; const enum ise derleme sırasında tamamen silinip kullanıldığı yerlere değeri yazılır. Enum, tiplerin aksine çalışma zamanında gerçek bir nesne üreten az sayıdaki TypeScript özelliğinden biridir.

Bu çalışma zamanı izi yüzünden birçok proje enum yerine string literal birleşimlerini veya as const nesneleri tercih ediyor. Aşağıda üç enum türünü, derlenmiş çıktılarını, isolatedModules ve erasableSyntaxOnly ile ilişkilerini ve alternatifleri tsc 6.0 ile denenmiş örneklerle karşılaştırıyoruz. Serinin geri kalanı için TypeScript öğrenme rehberi sayfasına bakabilirsiniz.

Sayısal enum

Sayısal enum

İlk üyeye değer vermezseniz 0 olur, sonraki her üye bir öncekinin bir fazlasıdır. Araya bir değer yazarsanız sayım oradan devam eder:

typescript
enum Durum {
  Beklemede,      // 0
  Hazirlaniyor,   // 1
  Kargoda = 10,
  Teslim,         // 11
}

console.log(Durum.Hazirlaniyor); // 1
console.log(Durum.Teslim);       // 11
console.log(Durum[10]);          // Kargoda

function etiket(d: Durum) {}
etiket(Durum.Kargoda);
etiket(1);   // geçerli: 1 bir Durum üyesinin değeri
etiket(99);
// TS2345: Argument of type '99' is not assignable to parameter of type 'Durum'.

Durum[10] ifadesinin "Kargoda" döndürmesi ters eşlemedir (reverse mapping). tsc bu enum'u şu JavaScript'e çevirir:

javascript
var Durum;
(function (Durum) {
    Durum[Durum["Beklemede"] = 0] = "Beklemede";
    Durum[Durum["Hazirlaniyor"] = 1] = "Hazirlaniyor";
    Durum[Durum["Kargoda"] = 10] = "Kargoda";
    Durum[Durum["Teslim"] = 11] = "Teslim";
})(Durum || (Durum = {}));

console.log(Object.keys(Durum));
// [ '0', '1', '10', '11', 'Beklemede', 'Hazirlaniyor', 'Kargoda', 'Teslim' ]

Ters eşleme yüzünden nesnede hem isimler hem sayılar anahtar olarak bulunur. Enum üyelerini Object.keys() ile listelemek istiyorsanız sayısal anahtarları ayıklamanız gerekir. TypeScript 5.0 sürüm notlarına göre bu sürümden itibaren bütün enum'lar "union enum" olarak ele alınır; her üyenin kendi tipi vardır ve Durum.Kargoda gibi üyeleri tip olarak da kullanabilirsiniz. Yukarıdaki etiket(99) hatası da bu sıkı denetimin sonucudur.

String enum

String enum'da her üyeye bir string literal (veya başka bir string enum üyesi) atamak zorundasınız; otomatik artış yoktur. Karşılığında çalışma zamanında anlamlı değerler görürsünüz ve ters eşleme üretilmez:

typescript
enum Rol {
  Yonetici = "admin",
  Editor = "editor",
  Okuyucu = "reader",
}

console.log(Rol.Editor);          // editor
console.log(Object.keys(Rol));    // [ 'Yonetici', 'Editor', 'Okuyucu' ]
console.log(Object.values(Rol));  // [ 'admin', 'editor', 'reader' ]

function yetki(r: Rol) {}
yetki(Rol.Yonetici);
yetki("admin");
// TS2345: Argument of type '"admin"' is not assignable to parameter of type 'Rol'.

Son satır string enum'ların en çok şaşırtan davranışıdır: değeri "admin" olan bir üye olsa bile düz "admin" metni Rol tipine atanamaz. API'den veya formdan gelen metni enum'a çevirmek için ayrıca bir kontrol yazmanız gerekir. Handbook sayı ve metin üyelerini karıştıran (heterogeneous) enum'ların teknik olarak mümkün olduğunu ama önerilmediğini belirtir.

const enum: derlemede silinen enum

const enum tanımı derlenen koda hiç girmez; üyeye yaptığınız her erişim yerine değerin kendisi yazılır:

typescript
const enum Yon {
  Yukari,
  Asagi,
  Sol,
  Sag,
}

const hareketler = [Yon.Yukari, Yon.Sag];
console.log(hareketler); // [ 0, 3 ]
javascript
// tsc çıktısı: Yon nesnesi yok, değerler satır içine yazıldı
const hareketler = [0 /* Yon.Yukari */, 3 /* Yon.Sag */];
console.log(hareketler);

preserveConstEnums seçeneği açıksa tanım normal enum gibi yine üretilir ama erişimler satır içi değer olarak kalır. Enum belgesi const enum'ların asıl riskinin .d.ts dosyalarındaki "ambient" const enum'lar olduğunu söyler: bir kütüphanenin A sürümündeki değerler derleme sırasında kodunuza gömülürken çalışma zamanında B sürümü yüklenebilir. Ayrıca tek dosya derleyen araçlar (Babel, esbuild gibi transpiler'lar) başka dosyadaki değeri bilemediği için isolatedModules açıkken ambient const enum'a erişim hata verir:

typescript
declare const enum Sayilar {
  Sifir = 0,
  Bir = 1,
}
console.log(Sayilar.Sifir + Sayilar.Bir);
// --isolatedModules ile:
// TS2748: Cannot access ambient const enums when 'isolatedModules' is enabled.

erasableSyntaxOnly ve Node.js'in tip silme modu

erasableSyntaxOnly ve Node.js'in tip silme modu

Node.js, TypeScript dosyalarını tip bilgisini silerek doğrudan çalıştırabiliyor. TypeScript 5.8 sürüm notlarına göre bu modda yalnızca silindiğinde geriye geçerli JavaScript bırakan sözdizimi desteklenir ve enum bu listede yer almaz. --erasableSyntaxOnly seçeneği bu kuralı derleyiciye denetletir. Hem normal enum hem const enum için şu hatayı aldık:

typescript
// tsc --erasableSyntaxOnly
enum Rol { Yonetici = "admin" }
// TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.

Kodunuzu Node.js'in tip silme moduyla veya benzer tek dosya araçlarıyla çalıştırmayı planlıyorsanız aşağıdaki alternatifler daha uygun olur. Node.js tarafındaki kurulum için TypeScript ile Node.js yazısına bakabilirsiniz.

Alternatif 1: string literal birleşimi

En sade seçenek, izin verilen değerleri bir union tipi olarak yazmaktır. Çalışma zamanında hiçbir kod üretmez ve düz metinle çağrılabilir:

typescript
type Rol = "admin" | "editor" | "reader";

function yetki(r: Rol) {
  return r.toUpperCase();
}
console.log(yetki("editor")); // EDITOR
yetki("yonetici");
// TS2345: Argument of type '"yonetici"' is not assignable to parameter of type 'Rol'.

Eksiksiz switch kontrolü ve never ile daraltma için narrowing yazısına, literal tiplerin ayrıntısı için literal tipler ve as const yazısına bakın.

Alternatif 2: as const nesne

Değerlere bir isimle erişmek ve onları çalışma zamanında da listelemek istiyorsanız as const nesne iyi bir orta yoldur. Enum belgesi de modern TypeScript'te bu kalıbın çoğu durumda yeteceğini ve kodu JavaScript'in kendisine yakın tuttuğunu belirtir:

typescript
const Durum = {
  Beklemede: "beklemede",
  Kargoda: "kargoda",
  Teslim: "teslim",
} as const;

// Değerlerden union tipi çıkarmak için bir satır gerekir
type Durum = (typeof Durum)[keyof typeof Durum]; // "beklemede" | "kargoda" | "teslim"

function guncelle(d: Durum) {
  return `Yeni durum: ${d}`;
}
console.log(guncelle(Durum.Kargoda)); // Yeni durum: kargoda
console.log(guncelle("teslim"));      // Yeni durum: teslim
console.log(Object.values(Durum));    // [ 'beklemede', 'kargoda', 'teslim' ]

Bu dosya --erasableSyntaxOnly ile de hatasız derlenir. typeof ve keyof operatörlerinin nasıl çalıştığını keyof, typeof ve indexed access yazısında anlattık.

Karşılaştırma tablosu

Karşılaştırma tablosu: Sayısal enum, String enum, const enum, Literal union
SeçenekÇalışma zamanı koduDüz değer kabul eder miDeğerleri listelemeerasableSyntaxOnly
Sayısal enumNesne + ters eşlemeGeçerli sayıları kabul ederObject.keys ile, sayılar karışıkHata verir
String enumNesneHayır, üye kullanılmalıObject.values ileHata verir
const enumYok (değer gömülür)Sayısal ise geçerli sayılarıMümkün değilHata verir
Literal unionYokEvetMümkün değilSorunsuz
as const nesneDüz nesneEvetObject.values ileSorunsuz

Hangisini seçmeli?

  • Yalnızca tip düzeyinde bir değer kümesi gerekiyorsa: literal union.
  • Değerlere isimle erişmek ve onları döngüyle gezmek gerekiyorsa: as const nesne.
  • Bit bayrakları (1 << 1 gibi sabit ifadeler) veya mevcut bir kod tabanında enum'larla tutarlılık gerekiyorsa: enum.
  • Projede isolatedModules, erasableSyntaxOnly veya tek dosya transpiler kullanılıyorsa: enum yerine ilk iki seçenek.

Sık yapılan hatalar

  • Sayısal enum üzerinde Object.keys() çağırıp yalnızca isimlerin geleceğini sanmak; ters eşleme sayıları da ekler.
  • String enum parametresine düz metin göndermeye çalışmak (TS2345).
  • Kütüphane .d.ts dosyalarında const enum yayınlamak; tüketiciler isolatedModules ile TS2748 alır.
  • Enum adını tip yerine anahtar listesi gibi kullanmak: anahtarların union'ı için keyof typeof Durum yazmanız gerekir.

Sık Sorulan Sorular

TypeScript enum kullanmak kötü mü?

Hayır, enum resmî ve desteklenen bir özelliktir. Ancak çalışma zamanı kodu ürettiği için tip silme tabanlı araçlarla uyumlu değildir. Projenizin derleme zinciri bunu destekliyorsa enum kullanabilirsiniz; desteklemiyorsa literal union veya as const nesne seçin.

Enum anahtarlarını tip olarak nasıl alırım?

keyof typeof Durum yazın. Enum belgesi bunun "Beklemede" | "Hazirlaniyor" | ... gibi bir string union verdiğini gösterir. Yalnızca keyof Durum yazmak beklediğiniz sonucu vermez.

const enum performans için daha mı iyi?

const enum üye erişimini değerle değiştirdiği için ek nesne ve özellik okuması oluşmaz. Belge bunun kendi projeniz içinde sorun olmadığını, riskin kütüphaneler arası paylaşılan ambient const enum'larda olduğunu vurgular.

isolatedModules açıkken normal enum kullanabilir miyim?

Evet. isolatedModules yalnızca ambient (declare ile tanımlanmış) const enum üyelerine erişimi yasaklar. erasableSyntaxOnly ise her türlü enum bildirimini yasaklar; ikisini karıştırmayın.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: TypeScript öğrenme rehberi · literal tipler ve as const · union ve intersection · keyof ve typeof · TypeScript ile Node.js · JavaScript Object metotları