Skip to content

Nega TypeScript Enum bilan Object.values() g‘alati natija beradi?

Chop etilgan: at 05:15

Yaqinda TypeScript’da kichik, lekin qiziqarli bir holatga duch keldim. Enum bilan ishlayotganda oddiygina Object.values() orqali qiymatlarni olishni xohlardim, lekin kutilmaganda ikkita turdagi ma’lumot qaytdi: string’lar va raqamlar.

Shunda o‘yladim: “Axir Object.values() faqat qiymatlarni qaytaradi-ku, nega enum’da bunday g‘alati natija chiqyapti?” O‘rganib chiqdim — aslida bu TypeScript’ning numeric enum mexanizmidagi maxsus xususiyat ekan.

Muammo qanday paydo bo‘ldi?

Keling, oddiy misol:

export enum StudentProgress {
  TenPercent = 10,
  ThirtyPercent = 30,
  FiftyPercent = 50,
  EightyPercent = 80,
  HundredPercent = 100,
}

console.log(Object.values(StudentProgress));

Men kutgan natija shunday edi:

[10, 30, 50, 80, 100]

Lekin haqiqiy natija esa shunaqa chiqdi

[
  'TenPercent',
  'ThirtyPercent',
  'FiftyPercent',
  'EightyPercent',
  'HundredPercent',
  10,
  30,
  50,
  80,
  100
]

Bir qaraganda chalkash: Object.values() faqat qiymatlarni olish kerak edi-ku, nega nomlari ham qaytdi?

Sirli sabab: TypeScript’dagi Reverse Mapping

TypeScript enum’lar aslida oddiy JavaScript obyektlari sifatida ishlaydi. Numeric enum ishlatilsa, TypeScript ikki tomonlama mapping yaratadi — ya’ni qiymatdan nomni ham olish mumkin.

Keling, yuqoridagi enum qanday kompilyatsiya bo‘lishini ko‘ramiz

var StudentProgress = {
  10: "TenPercent",
  30: "ThirtyPercent",
  50: "FiftyPercent",
  80: "EightyPercent",
  100: "HundredPercent",
  TenPercent: 10,
  ThirtyPercent: 30,
  FiftyPercent: 50,
  EightyPercent: 80,
  HundredPercent: 100
};

Ko‘rdingmi? TypeScript har bir qiymat uchun ikki juftlik yaratgan:

Shuning uchun Object.values() ikkala tomonni ham ko‘radi — nomlar ham, qiymatlar ham chiqadi.

Reverse Mapping nima uchun kerak?

Bu imkoniyat TypeScript enum’larini qulay qiladi. Masalan:

StudentProgress.TenPercent; // 10
StudentProgress[10]; // "TenPercent"

Demak, enum qiymatidan nomini olish ham mumkin. Bu “reverse mapping” deb ataladi — va aynan shu sababdan Object.values() natijasi kutilmagandan uzunroq chiqadi.

Qanday qilib faqat “values” olish mumkin?

Agar bizga faqat raqamli qiymatlar kerak bo‘lsa, oddiy filter bilan hal qilish mumkin:

Object.values(StudentProgress).filter(v => typeof v === 'number');

Natija:

[10, 30, 50, 80, 100]

Yoki, agar faqat nomlar kerak bo‘lsa:

Object.values(StudentProgress).filter(v => typeof v === 'string');

Alternativa: String enum ishlatish

Agar sen reverse mapping xatti-harakatini xohlamasang, string enum ishlat. U holda TypeScript teskari mapping yaratmaydi:

export enum StudentProgress {
  TenPercent = '10',
  ThirtyPercent = '30',
  FiftyPercent = '50',
  EightyPercent = '80',
  HundredPercent = '100',
}

console.log(Object.values(StudentProgress));
// ["10", "30", "50", "80", "100"]

Natija toza va aniq bo‘ladi.

Xulosa

Bu kichik tajriba menga shuni o‘rgatdi:

Bonus: “Nega bunday qilgan TypeScript jamoasi?”

TypeScript ishlab chiquvchilari bu dizaynni tanlagan, chunki u eski JavaScript’dagi enum-like pattern’larni (masalan, const Status = { 0: 'Active', Active: 0 }) moslashtirish uchun. Ya’ni, type safety va JS mosligini birlashtirish uchun shu yondashuv tanlangan.

Shaxsiy xulosa:

“Kutilmagan natija” aslida “kutishim noto‘g‘ri bo‘lgani” sababli edi. TypeScript enum’lari haqida to‘liq tushunchaga ega bo‘lmagunimcha, Object.values() natijasi menga g‘alati tuyuldi. Endi esa bu dizayn qarori mantiqan to‘g‘ri ekanini tushundim.


Keyingi maqola
Uylanganimga 30 kun: hayotimdagi eng katta o‘zgarishlar