Mundarija (39)
- Bu darsda
- 1. Nega bu kerak?
- 2. Sonli enum
- 2.1 Yozuv va qiymatlar
- 2.2 enum — ham tur, ham qiymat
- 2.3 Reverse mapping: raqamdan nomga
- 3. enum JavaScript'da nimaga aylanadi?
- 3.1 tsc chiqishi
- 3.2 Node 24: "strip-only rejimida qo'llab-quvvatlanmaydi"
- 3.3 erasableSyntaxOnly: xatoni yozish paytida ko'rish
- 4. Satrli enum
- 4.1 Har a'zoga satr
- 4.2 Satrli enum satrni qabul qilmaydi
- 5. Sonli enum tuzog'i: istalgan son o'tadi
- 6. const enum
- 6.1 Obyektsiz enum
- 6.2 enum turlari — xulosa
- 7. Muqobil 1: literal union
- 7.1 Eng sodda yo'l
- 7.2 To'liqlik tekshiruvi union bilan
- 8. Muqobil 2: as const obyekt
- 8.1 Qachon obyekt kerak?
- 8.2 Obyektdan union chiqarish
- 8.3 Har holatga matn: satisfies Record
- 8.4 Massivdan union: ro'yxat ham, tur ham
- 9. Qachon enum ni ko'rasiz?
- 10. Ko'p uchraydigan xatolar
- 10.1 Node'da enum
- 10.2 Sonli enum'ni Object.keys bilan aylanish
- 10.3 Satrli enum'ga satr berish
- 10.4 as const ni unutish
- 10.5 Serverdan kelgan satrga ko'r-ko'rona ishonish
- 11. Mashqlar
- 1-mashq (oson): Qiymatlarni ayting
- 2-mashq (o'rta): enum ni union'ga ko'chiring
- 3-mashq (qiyin): Amaliy tajriba — buyurtma holatlari
- 12. Real ishda
- Xulosa
- Manbalar
TypeScript enum va uning muqobillari: as const obyekt va literal union
Qisqacha:
enum— nomlangan doimiylar to'plami:enum OrderStatus { New, Ready }. U TypeScript'ning kam sonli "kod qo'shadigan" imkoniyatlaridan:tscundan JavaScript obyekti yasaydi. Shuning uchun Node 24.tsfaylidagienumni bajarmaydi,erasableSyntaxOnlyesa uni taqiqlaydi. Muqobili — literal union ("yangi" | "tayyor") yokias constobyekt va undan chiqarilgan union.
Bu darsda
- Sonli va satrli
enumyozasiz, reverse mapping va avtomatik raqamlashni tushunasiz. tscenumdan qanday JavaScript yasashini ko'rasiz vaconst enumfarqini bilasiz.- Sonli
enumning tur tuzog'ini taniysiz. - Nega Node type stripping va
erasableSyntaxOnlyenumni taqiqlashini tushuntira olasiz. enumni literal union vaas constobyekt bilan almashtirasiz —vazifalardagi kabi.
Oldin bilishingiz kerak: Klasslar TypeScript'da, Union va literal turlar, Discriminated union va to'liqlik tekshiruvi, Massiv va tuple turlari (as const).
1. Nega bu kerak?
O'tgan darsda parameter properties JavaScript'ga kod qo'shgani uchun Node uni bajarmasligini ko'rdik. enum — xuddi shunday sintaksisning eng mashhur vakili. Uni bilish shart: eski loyihalarda, kutubxonalarda va intervyularda juda ko'p uchraydi. Lekin yangi kodda undan qochish ham kerak.
Avval muammo. «Bahor» oshxonasida buyurtma holatlari raqamlar bilan saqlanardi:
// 0 — yangi, 1 — tayyorlanmoqda, 2 — tayyor
const order = { id: 7, status: 1 };
if (order.status === 2) {
console.log("Olib keting!");
}
order.status = 5;
console.log(order.status); // 51 nima? Izohsiz hech kim bilmaydi. 5 — mavjud bo'lmagan holat, lekin JavaScript uni bemalol qabul qildi. "Sehrli raqamlar" (magic numbers) — kod o'qishni qiyinlashtiradigan va jim xatoga yo'l ochadigan narsa. Holatlarga nom berish kerak, va faqat ruxsat etilgan qiymatlar o'tishi kerak.
2. Sonli enum
2.1 Yozuv va qiymatlar
Enum (enumeration — "sanab chiqish") — nomlangan doimiylar to'plami:
enum OrderStatus {
New,
Cooking,
Ready,
}
console.log(OrderStatus.New, OrderStatus.Ready); // 0 2Qiymat berilmasa, a'zolar 0 dan boshlab raqamlanadi: New — 0, Cooking — 1, Ready — 2. Endi kodda status === 2 o'rniga status === OrderStatus.Ready yoziladi — sehrli raqam nom oldi.
Boshlang'ich qiymatni o'zingiz berishingiz mumkin. Keyingi a'zolar undan davom etadi:
enum Hour {
Open = 7,
Lunch = 12,
AfterLunch,
}
console.log(Hour.AfterLunch); // 13AfterLunch ga qiymat berilmadi — u oldingisidan bittaga ko'p: 13.
2.2 enum — ham tur, ham qiymat
OrderStatus ikki ma'noda ishlaydi. Tur sifatida — "faqat shu holatlardan biri":
enum OrderStatus {
New,
Cooking,
Ready,
}
const status: OrderStatus = 42;Kompilyator:
TS2322: Type '42' is not assignable to type 'OrderStatus'.42 — enum a'zolarining birortasi ham emas. Qiymat sifatida esa OrderStatus — haqiqiy JavaScript obyekti, uni konsolga chiqarish, aylanib chiqish mumkin. Buni keyingi bo'limda ko'ramiz.
2.3 Reverse mapping: raqamdan nomga
Sonli enum'da teskari yo'l ham bor — raqam bo'yicha nom olish:
enum OrderStatus {
New,
Cooking,
Ready,
}
console.log(OrderStatus[1]); // Cooking
console.log(Object.keys(OrderStatus));Konsolda:
Cooking
[ '0', '1', '2', 'New', 'Cooking', 'Ready' ]Bu reverse mapping (teskari moslash) deyiladi. Ikkinchi qatorga qarang: obyektda oltita kalit bor — uchta nom va uchta raqam. Nega? Javob — tsc yasagan JavaScript'da.
3. enum JavaScript'da nimaga aylanadi?
3.1 tsc chiqishi
Oddiy turlar (: number, interface) JavaScript'da shunchaki o'chib ketadi. enum esa tsc 7.0.2 da shunday kodga aylanadi:
var OrderStatus;
(function (OrderStatus) {
OrderStatus[OrderStatus["New"] = 0] = "New";
OrderStatus[OrderStatus["Cooking"] = 1] = "Cooking";
OrderStatus[OrderStatus["Ready"] = 2] = "Ready";
})(OrderStatus || (OrderStatus = {}));Bir qatorni sekin o'qiymiz: OrderStatus[OrderStatus["New"] = 0] = "New". Ichkaridagi OrderStatus["New"] = 0 — obyektga New: 0 yozadi va 0 ni qaytaradi. Tashqaridagisi esa OrderStatus[0] = "New" bo'ladi. Bitta qatorda ikki yo'nalish yoziladi — shuning uchun oltita kalit.
(function (…) { … })(…) — o'zi darhol chaqiriladigan funksiya (IIFE). Bu eski uslub: var va IIFE — ES modullardan oldingi JavaScript'ning naqshi (var va nega undan voz kechildi darsidagi davr). Ya'ni enum — TypeScript'ga ES modullardan ancha oldin, uning ilk versiyalarida qo'shilgan imkoniyat.
Buni rasmda ko'raylik — bitta .ts fayl ikki xil yo'l bilan ishga tushadi:
flowchart LR
A["status.ts<br/>enum OrderStatus"] --> B["tsc"]
A --> C["node status.ts<br/>(type stripping)"]
B --> D["status.js<br/>var + IIFE"]
C --> E["ERR_UNSUPPORTED_<br/>TYPESCRIPT_SYNTAX"]
F["type Status =<br/>'yangi' | 'tayyor'"] --> G["node: tur o'chadi"]
G --> H["ishlaydi"]Tepada enum — tsc uni JavaScript'ga tarjima qiladi, Node esa tarjima qilmaydi. Pastda union — u faqat tur, o'chiriladi va ikkala yo'lda ham ishlaydi.
3.2 Node 24: "strip-only rejimida qo'llab-quvvatlanmaydi"
TypeScript'ni o'rnatish darsida Node 24 .ts faylni turlarini o'chirib (type stripping) ishga tushirishini ko'rdik. enum ni o'chirib bo'lmaydi — uning o'rniga yuqoridagi IIFE yozilishi kerak. Node buni qilmaydi:
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only modeTarjimasi: "TypeScript enum i faqat-o'chirish rejimida qo'llab-quvvatlanmaydi". Node'da --experimental-transform-types bayrog'i bor: u enum ni ham o'giradi. Lekin nomidan ko'rinib turibdiki, u tajribaviy (experimental) — ishga tushganda ogohlantirish chiqaradi va xulqi o'zgarishi mumkin.
3.3 erasableSyntaxOnly: xatoni yozish paytida ko'rish
Klasslar TypeScript'da darsidagi bayroq enum ni ham ushlaydi:
// @ts-options: {"erasableSyntaxOnly": true}
enum OrderStatus {
New,
Ready,
}Kompilyator:
TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.Tarjimasi: "erasableSyntaxOnly yoqilganda bu sintaksisga ruxsat yo'q". TypeScript aytyapti: "bu enum ni o'chirib bo'lmaydi, Node uni bajara olmaydi". "O'chiriladigan sintaksis" bayrog'i TypeScript 5.8 da (2025-yil boshi) aynan shu maqsadda qo'shildi: Node, Deno, Bun kabi muhitlar .ts ni turlarini o'chirib bajaradi. Bayroq "faqat shunday muhitda ishlaydigan kod yoz" deydi. U taqiqlaydigan to'rt narsa: enum, qiymatli namespace, parameter properties va import x = require(…) kabi eski import shakli.
Mashqlar papkangizda ham, vazifalar da ham bu bayroq yoqilgan. vazifalar ning AGENTS.md faylidagi qoida: "Faqat o'chirib bo'ladigan TS: enum, namespace, konstruktor parametr xususiyatlari yo'q".
Tekshirib ko'ring:
enum Size { S = 10, M, L = 30, XL }—Size.MvaSize.XLqiymatlari qanday?
Javob
Size.M — 11 (oldingi 10 dan keyin), Size.XL — 31 (oldingi 30 dan keyin). Qiymat berilmagan sonli a'zo doim oldingi a'zodan bittaga ko'p.
4. Satrli enum
4.1 Har a'zoga satr
Raqamlar loglarda va JSON'da tushunarsiz: "status": 1. Satrli enum'da har a'zo o'z matnini oladi:
enum Payment {
Cash = "naqd",
Card = "karta",
}
console.log(Payment.Card);
console.log(Object.keys(Payment), Object.values(Payment));Konsolda:
karta
[ 'Cash', 'Card' ] [ 'naqd', 'karta' ]Satrli enum'da reverse mapping yo'q: tsc faqat Payment["Cash"] = "naqd" yozadi. Kalitlar — faqat nomlar.
4.2 Satrli enum satrni qabul qilmaydi
Mana kutilmagan joy:
enum Payment {
Cash = "naqd",
Card = "karta",
}
function pay(method: Payment): string {
return `To'lov: ${method}`;
}
pay("karta");Kompilyator:
TS2345: Argument of type '"karta"' is not assignable to parameter of type 'Payment'.Tarjimasi: ""karta" turidagi argumentni Payment turidagi parametrga berib bo'lmaydi". Qiymat bir xil — "karta", lekin TypeScript qabul qilmaydi: faqat Payment.Card deb yozish kerak. Satrli enum — TypeScript'dagi kam sonli nominal turlardan biri: unda nom muhim, shakl emas (Strukturaviy tiplash darsidagi qoidaning istisnosi).
Bu ba'zan foydali (tasodifiy satr o'tib ketmaydi), lekin ko'pincha noqulay. Serverdan JSON keladi: {"method": "karta"}. Bu oddiy satr, enum emas — har safar o'girish kerak bo'ladi.
5. Sonli enum tuzog'i: istalgan son o'tadi
42 literalini OrderStatus ga berish xato edi. Lekin number turidagi o'zgaruvchi-chi?
enum OrderStatus {
New,
Cooking,
Ready,
}
const fromServer: number = 42;
const status: OrderStatus = fromServer;
console.log(status, OrderStatus[status]); // 42 undefinedtsc — xatosiz. number turidagi har qanday qiymat sonli enum'ga beriladi. Natija: status turi OrderStatus, qiymati esa mavjud bo'lmagan 42. Turi bor, ma'nosi yo'q.
Nega TypeScript bunga ruxsat beradi? Sonli enum'ning bir eski qo'llanishi — bit bayroqlari (bit flags): har a'zo ikkining darajasi, ular | (bitli "yoki") bilan birlashtiriladi:
enum Access {
Read = 1,
Write = 2,
Delete = 4,
}
const cashier: Access = Access.Read | Access.Write;
console.log(cashier); // 3
console.log((cashier & Access.Write) !== 0); // true
console.log((cashier & Access.Delete) !== 0); // falseKassirga o'qish va yozish ruxsati berildi: 1 + 2 = 3. 3 esa enum'da nomli a'zo emas — lekin to'g'ri qiymat. & (bitli "va") bilan har ruxsat alohida tekshiriladi. Shunday qiymatlar o'tishi uchun TypeScript sonli enum'ga istalgan number ni qabul qiladi — va shu bilan tasodifiy 42 ham o'tib ketadi. Bit amallari kundalik veb-ishda kam uchraydi, ularni hozir chuqur o'rganish shart emas.
Satrli enum'da bunday teshik yo'q. Literal union'da ham yo'q: number ni 0 | 1 | 2 ga berib bo'lmaydi.
6. const enum
6.1 Obyektsiz enum
const enum — tsc obyekt yaratmaydigan enum. Har ishlatilgan joyga qiymatning o'zi qo'yiladi:
const enum Size {
S,
M,
L,
}
console.log(Size.M); // 1tsc chiqishi — bitta qator, Size obyekti umuman yo'q:
console.log(1 /* Size.M */);Kichikroq va tezroq ko'rinadi. Lekin bu yozuvning o'z muammolari bor. Birinchisi: Size[1] (reverse mapping) ishlamaydi. Ikkinchisi jiddiyroq: const enum boshqa fayldan import qilinsa, har faylni alohida o'giradigan vositalar (Babel, esbuild, Node type stripping) uning qiymatini bila olmaydi — ular boshqa faylni o'qimaydi. TypeScript hujjatlari kutubxonalarda const enum ni eksport qilmaslikni tavsiya qiladi. erasableSyntaxOnly ham uni taqiqlaydi (TS1294).
6.2 enum turlari — xulosa
Sonli enum |
Satrli enum |
const enum |
|
|---|---|---|---|
| JavaScript'da | obyekt (IIFE) | obyekt (IIFE) | yo'q, qiymat qo'yiladi |
| Reverse mapping | bor | yo'q | yo'q |
Istalgan number o'tadimi |
ha (tuzoq) | — | ha |
| Node type stripping | yo'q | yo'q | yo'q |
Tekshirib ko'ring:
enum Level { Low = "past", High = "baland" }—Object.keys(Level).lengthnechaga teng? Sonlienum Level { Low, High }da-chi?
Javob
Satrli enum'da — 2 (Low, High): reverse mapping yo'q. Sonli enum'da — 4 ("0", "1", Low, High): har a'zo ikki yo'nalishda yoziladi. Shuning uchun sonli enum'ni Object.keys bilan aylanish xato beradi — raqamlar ham aralashib keladi.
7. Muqobil 1: literal union
7.1 Eng sodda yo'l
Union va literal turlar darsida bu yo'lni bilasiz:
type OrderStatus = "yangi" | "tayyorlanmoqda" | "tayyor";
function canServe(status: OrderStatus): boolean {
return status === "tayyor";
}
console.log(canServe("tayyor")); // trueEnum bilan solishtiring:
- JavaScript'da hech narsa qolmaydi — tur o'chadi,
"tayyor"oddiy satr. Node type stripping,erasableSyntaxOnly— hammasi rozi. - JSON bilan tabiiy ishlaydi — serverdan kelgan
"tayyor"aynan shu qiymat, o'girish kerak emas. - Noto'g'ri qiymat — darhol xato:
canServe("Tayyor")—TS2345. Muharrir avtomatik to'ldirishda uchta variantni taklif qiladi. - Sonli enum teshigi yo'q: istalgan satr
OrderStatusga o'tmaydi.
vazifalar da hamma "enum'simon" turlar shunday yozilgan (turlar.ts):
export type Filtr = "hammasi" | "faol" | "bajarilgan";
export type Saralash = "standart" | "yangi" | "alifbo";
export type TarmoqHolati =
"yuklanmoqda" | "tayyor" | "xato" | "oflayn";7.2 To'liqlik tekshiruvi union bilan
Discriminated union darsidagi never tekshiruvi union bilan ham ishlaydi. Yangi holat qo'shilsa, switch uni unutganini tsc aytadi:
type OrderStatus = "yangi" | "tayyor" | "bekor";
function isFinal(status: OrderStatus): boolean {
switch (status) {
case "yangi":
return false;
case "tayyor":
return true;
default: {
const rest: never = status;
return rest;
}
}
}Kompilyator:
TS2322: Type '"bekor"' is not assignable to type 'never'.""bekor" ni never ga berib bo'lmaydi" — ya'ni switch da "bekor" uchun case yo'q. Xabar unutilgan qiymatning nomini ham aytadi.
Tekshirib ko'ring:
type Pay = "naqd" | "karta"vaenum Pay2 { Cash = "naqd", Card = "karta" }. Serverdan{"method": "karta"}keldi vaJSON.parseqildingiz. Qaysi turga uni o'girishsiz berish oson?
Javob
Pay ga. Union — oddiy satrlar to'plami, "karta" unga to'g'ridan-to'g'ri mos (avval qiymat ruxsat etilganini tekshirish kerak, albatta). Pay2 esa satrni qabul qilmaydi — Pay2.Card kerak. Tekshirilgan satrni enum'ga aylantirish uchun qo'shimcha moslash kodi yoziladi.
8. Muqobil 2: as const obyekt
8.1 Qachon obyekt kerak?
Literal union faqat tur. Ba'zan esa holatlar ishlash paytida ham kerak: ro'yxatini chiqarish, OrderStatus.Ready kabi nom bilan murojaat qilish (masalan, enum'li eski kodni ko'chirayotganda). Buning uchun Massiv va tuple turlari darsidagi as const obyektga qo'llanadi:
const ORDER_STATUS = {
New: "yangi",
Cooking: "tayyorlanmoqda",
Ready: "tayyor",
} as const;
console.log(ORDER_STATUS.Ready);
console.log(Object.values(ORDER_STATUS));Konsolda:
tayyor
[ 'yangi', 'tayyorlanmoqda', 'tayyor' ]as const siz hover'da { New: string; Cooking: string; Ready: string } bo'lardi — qiymatlar string ga kengayardi. as const bilan esa { readonly New: "yangi"; readonly Cooking: "tayyorlanmoqda"; readonly Ready: "tayyor" } — har qiymat literal tur va hammasi readonly. Bu — oddiy JavaScript obyekti, o'chiriladigan hech narsa yo'q, faqat as const turi o'chadi.
8.2 Obyektdan union chiqarish
Endi obyektdagi qiymatlardan union turini avtomatik yasaymiz, ikkinchi marta yozmasdan:
const ORDER_STATUS = {
New: "yangi",
Cooking: "tayyorlanmoqda",
Ready: "tayyor",
} as const;
type OrderStatus = (typeof ORDER_STATUS)[keyof typeof ORDER_STATUS];
function label(status: OrderStatus): string {
return status === ORDER_STATUS.Ready ? "Olib keting!" : "Kuting";
}
console.log(label("tayyor")); // Olib keting!
console.log(label(ORDER_STATUS.New)); // KutingOrderStatus turi — "yangi" | "tayyorlanmoqda" | "tayyor". Uzun ifodani qismlarga ajratib o'qiymiz:
| Qism | Ma'nosi | Natija |
|---|---|---|
typeof ORDER_STATUS |
obyektning turi | { readonly New: "yangi"; … } |
keyof typeof ORDER_STATUS |
uning kalitlari | "New" | "Cooking" | "Ready" |
(…)[keyof …] |
shu kalitlardagi qiymatlar | "yangi" | "tayyorlanmoqda" | "tayyor" |
Bu uch operatorni (keyof, typeof va indexed access) keyingi darslarda alohida o'rganamiz. Hozircha bu qatorni tayyor qolip deb bilish yetarli: "obyekt qiymatlarining union'i".
Qiymat va tur bir xil nom (OrderStatus) bilan ham yozilishi mumkin — TypeScript qiymatlar va turlarni alohida saqlaydi. Ko'p loyihalar shunday qiladi: OrderStatus.Ready (qiymat) va status: OrderStatus (tur) — xuddi enum'dagidek o'qiladi.
Endi label ham ORDER_STATUS.New ni, ham oddiy "tayyor" satrini qabul qiladi. Satrli enum'dagi noqulaylik yo'q.
8.3 Har holatga matn: satisfies Record
Holatlar uchun ekrandagi matnlar — Index signature va Record darsidagi Record<Union, V> ning tabiiy joyi. satisfies bilan tekshiramiz:
type OrderStatus = "yangi" | "tayyor" | "bekor";
const LABELS = {
yangi: "Qabul qilindi",
tayyor: "Tayyor",
} satisfies Record<OrderStatus, string>;Kompilyator:
TS2741: Property 'bekor' is missing in type '{ yangi: string; tayyor: string; }' but required in type 'Record<OrderStatus, string>'.Tarjimasi: "bekor xususiyati { yangi: string; tayyor: string; } turida yo'q, lekin Record<OrderStatus, string> da majburiy". Holat qo'shildi — matn unutildi — tsc darhol eslatdi. vazifalar dagi aloqaMatnlari (satisfies Record<TarmoqHolati, string>) aynan shunday.
8.4 Massivdan union: ro'yxat ham, tur ham
Holatlarga nom (ORDER_STATUS.Ready) kerak bo'lmasa, faqat ro'yxat yetarli bo'lsa, as const massiv yanada sodda:
const SIZES = ["kichik", "o'rta", "katta"] as const;
type Size = (typeof SIZES)[number];
function isSize(text: string): text is Size {
return SIZES.some((s) => s === text);
}
console.log(isSize("o'rta"), isSize("XL")); // true false(typeof SIZES)[number] — "massivning istalgan raqamli indeksidagi element turi", ya'ni "kichik" | "o'rta" | "katta". Ro'yxat bir marta yoziladi: undan ham tugmalar chiziladi, ham tur chiqadi. vazifalar dagi FILTRLAR ham ro'yxat, lekin teskari yo'l bilan: avval Filtr turi, keyin unga mos readonly Filtr[] massiv. Ikkala yo'l ham ishlaydi — muhimi, biri o'zgarsa tsc ikkinchisini eslatsin.
Tekshirib ko'ring:
const SIZE = { S: "kichik", L: "katta" };(as constsiz) dan(typeof SIZE)[keyof typeof SIZE]qanday tur beradi?
Javob
string. as const bo'lmasa, obyekt qiymatlari string ga kengayadi, qiymatlar union'i ham string bo'ladi — literal ro'yxat yo'qoladi. as const — bu usulning yuragi.
9. Qachon enum ni ko'rasiz?
enum noto'g'ri emas — u ishlaydi va tsc bilan build qilinadigan loyihalarda (Angular, ko'p korporativ kodlar) keng tarqalgan. Siz uni o'qiy olishingiz va o'zgartira olishingiz shart. Yangi kodda tanlov mezonlari:
| Holat | Tanlov |
|---|---|
| Faqat tur kerak (parametr, maydon) | literal union |
| Qiymatlar ro'yxati ishlash paytida ham kerak | as const obyekt + union |
erasableSyntaxOnly yoki Node type stripping |
faqat yuqoridagi ikkitasi |
Eski loyihada enum bor |
uslubni saqlang, ko'chirish — alohida qaror |
10. Ko'p uchraydigan xatolar
10.1 Node'da enum
ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX: TypeScript enum is not supported in strip-only mode. Tuzatish: literal union yoki as const obyekt. erasableSyntaxOnly ni yoqing — xato tsc da ko'rinadi (TS1294).
10.2 Sonli enum'ni Object.keys bilan aylanish
Nomlar bilan birga raqamlar ham keladi. Tuzatish: as const obyekt va Object.values.
10.3 Satrli enum'ga satr berish
TS2345: Argument of type '"karta"' is not assignable to parameter of type 'Payment'. Tuzatish: Payment.Card yoki — yaxshisi — union turi.
10.4 as const ni unutish
(typeof X)[keyof typeof X] — string. Tuzatish: obyekt oxirida as const.
10.5 Serverdan kelgan satrga ko'r-ko'rona ishonish
const s = json.status as OrderStatus — tekshiruvsiz va'da. Tuzatish: ruxsat etilgan qiymatlar ro'yxatidan find bilan qidiring (3-mashqdagi parseStatus).
11. Mashqlar
1-mashq (oson): Qiymatlarni ayting
enum Table {
Window = 1,
Corner,
Terrace = 10,
Hall,
}
console.log(Table.Corner + Table.Hall); // 13Table.Corner qiymati: [:2]. Table.Hall qiymati: [:11]. Object.keys(Table).length: .
Yechim
Corner— 2:Window = 1dan keyingisi.Hall— 11:Terrace = 10dan keyingisi. 2 + 11 = 13.- 8: sonli enum'da har a'zo ikki marta — nom va raqam (
"1","2","10","11"va to'rtta nom).
2-mashq (o'rta): enum ni union'ga ko'chiring
Bu kod tsc bilan build qilinganda ishlaydi, lekin Node 24 da ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX beradi. Yana bir kamchiligi: yangi yetkazish turi qo'shilsa, if uni jim "kuryer" narxiga tushirib yuboradi:
enum Delivery {
Pickup = "olib ketish",
Courier = "kuryer",
}
function deliveryFee(type: Delivery, km: number): number {
if (type === Delivery.Pickup) return 0;
return 10000 + km * 2000;
}Uni enum'siz yozing: as const obyekt DELIVERY, undan chiqarilgan type Delivery, va deliveryFee — switch + never bilan (yangi yetkazish turi qo'shilsa, tsc aytsin).
Yechim
// @ts-options: {"erasableSyntaxOnly": true}
const DELIVERY = {
Pickup: "olib ketish",
Courier: "kuryer",
} as const;
type Delivery = (typeof DELIVERY)[keyof typeof DELIVERY];
function deliveryFee(type: Delivery, km: number): number {
switch (type) {
case "olib ketish":
return 0;
case "kuryer":
return 10000 + km * 2000;
default: {
const rest: never = type;
return rest;
}
}
}
console.log(deliveryFee(DELIVERY.Courier, 3)); // 16000
console.log(deliveryFee("olib ketish", 3)); // 0erasableSyntaxOnlyyoqilgan — kod o'chiriladigan sintaksisda, Node uni bajaradi.DELIVERY.Courierham, oddiy"olib ketish"ham qabul qilinadi.DELIVERYgaDrone: "dron"qo'shsangiz,defaultdagi qatorTS2322: Type '"dron"' is not assignable to type 'never'.beradi.
3-mashq (qiyin): Amaliy tajriba — buyurtma holatlari
Mashq kurs/mashqlar/15/ papkasida (erasableSyntaxOnly yoqilgan). 19-holatlar/status.ts ni avval enum bilan yozing:
// 19-holatlar/status.ts — birinchi variant (enum bilan)
export enum OrderStatus {
New = "yangi",
Cooking = "tayyorlanmoqda",
Ready = "tayyor",
Served = "berildi",
}
export function nextStatus(s: OrderStatus): OrderStatus {
switch (s) {
case OrderStatus.New:
return OrderStatus.Cooking;
case OrderStatus.Cooking:
return OrderStatus.Ready;
default:
return OrderStatus.Served;
}
}npx tsc --pretty false va node --test 19-holatlar/status.test.ts (bitta oddiy test bilan) nima deydi? Keyin enum'siz qayta yozing:
ORDER_STATUS—as constobyekt,OrderStatus— undan union.STATUS_LABELS— har holatga o'zbekcha matn,satisfies Record<OrderStatus, string>.nextStatus(s)—switch+never(defaultsiz qolgan holat yo'q).parseStatus(text: string): OrderStatus— serverdan kelgan matn; noma'lum bo'lsaTypeError. Ishora:Object.values(ORDER_STATUS).find((s) => s === text)—findqiymatni ham, turni ham toraytiradi (vazifalardagiFILTRLAR.findkabi).
Testlar: holatlar ketma-ketligi, parseStatus (to'g'ri, katta harfli "Tayyor", "1"), matnlar.
Yechim
Birinchi variantda tsc 7.0.2:
19-holatlar/status.ts(2,13): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.node --test esa testgacha yetmadi — modul yuklanishida to'xtadi:
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode
✖ 19-holatlar\status.test.ts (194.4799ms)Ikkalasi bitta sababni aytadi: enum o'chirib bo'lmaydigan sintaksis. tsc buni yozish paytida, Node — ishga tushirish paytida ko'rsatdi.
// 19-holatlar/status.ts — buyurtma holatlari (enum'siz)
export const ORDER_STATUS = {
New: "yangi",
Cooking: "tayyorlanmoqda",
Ready: "tayyor",
Served: "berildi",
} as const;
export type OrderStatus =
(typeof ORDER_STATUS)[keyof typeof ORDER_STATUS];
// Har holatga ekrandagi matn — biri unutilsa, tsc aytadi
export const STATUS_LABELS = {
yangi: "Qabul qilindi",
tayyorlanmoqda: "Tayyorlanmoqda",
tayyor: "Tayyor",
berildi: "Mehmonga berildi",
} satisfies Record<OrderStatus, string>;
export function nextStatus(s: OrderStatus): OrderStatus {
switch (s) {
case "yangi":
return "tayyorlanmoqda";
case "tayyorlanmoqda":
return "tayyor";
case "tayyor":
case "berildi":
return "berildi";
default: {
const rest: never = s;
return rest;
}
}
}
// Serverdan kelgan matn → holat (yoki xato)
export function parseStatus(text: string): OrderStatus {
const found = Object.values(ORDER_STATUS).find((s) => s === text);
if (found === undefined) {
throw new TypeError(`Noma'lum holat: ${text}`);
}
return found;
}// 19-holatlar/status.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import {
ORDER_STATUS,
STATUS_LABELS,
nextStatus,
parseStatus,
} from "./status.ts";
test("nextStatus: holatlar ketma-ketligi", () => {
assert.equal(nextStatus(ORDER_STATUS.New), "tayyorlanmoqda");
assert.equal(nextStatus("tayyorlanmoqda"), "tayyor");
assert.equal(nextStatus("berildi"), "berildi");
});
test("parseStatus: serverdan kelgan matn", () => {
assert.equal(parseStatus("tayyor"), ORDER_STATUS.Ready);
assert.throws(() => parseStatus("Tayyor"), TypeError);
assert.throws(() => parseStatus("1"), TypeError);
});
test("STATUS_LABELS: har holatga matn", () => {
const all = Object.values(ORDER_STATUS);
assert.equal(all.length, 4);
assert.equal(STATUS_LABELS[parseStatus("tayyor")], "Tayyor");
});Object.values(ORDER_STATUS)—("yangi" | "tayyorlanmoqda" | "tayyor" | "berildi")[], sonli enum'dagi raqamlar aralashmaydi.findnatijasi —OrderStatus | undefined, tekshiruvdan keyinOrderStatus.case "tayyor": case "berildi":— ikkicasebitta javobga tushadi (oxirgi holat o'zida qoladi).parseStatus("Tayyor")— xato: holatlar katta-kichik harfga sezgir, server aynan"tayyor"yuborishi kerak.
npx tsc --pretty false — chiqishsiz. node --test 19-holatlar/status.test.ts bizda (Node 24.21.0) shunday chiqdi:
✔ nextStatus: holatlar ketma-ketligi (3.7521ms)
✔ parseStatus: serverdan kelgan matn (1.6521ms)
✔ STATUS_LABELS: har holatga matn (0.485ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 365.1981XATOLAR.md ga qo'shing: TS1294 (enum), Node'ning ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX, satrli enum'ga satr (TS2345), satisfies Record dagi TS2741. Keyin kurs/mashqlar papkasidan:
git add 15/19-holatlar 15/XATOLAR.md
git commit -m "15/19: status.ts — enum o'rniga as const va union"12. Real ishda
- Eski kod va kutubxonalar: Angular, ko'p korporativ loyihalar va avtomatik yaratiladigan API mijozlarida
enumko'p. Uni o'qish, IIFE chiqishini tanish va reverse mapping'ni bilish — majburiy ko'nikma. - Zamonaviy yo'nalish: Node, Deno, Bun
.tsni type stripping bilan bajaradi, ko'p jamoalarerasableSyntaxOnlyni yoqadi. Shuning uchun yangi kodda union vaas constobyekt tobora ko'proq uchraydi. - API va JSON: literal union serverdan kelgan satr bilan to'g'ridan-to'g'ri mos. Uni ishlash paytida tekshirish (
find, keyinroq Zod) — API ma'lumotlarini tiplash darsida. - Intervyu: "
enumva union farqi?", "Reverse mapping nima?", "const enumqachon xavfli?", "Nega Nodeenumni bajarmaydi?" — tez-tez so'raladi.
Xulosa
enum— nomlangan doimiylar: sonli (0 dan, reverse mapping bilan) va satrli (reverse mapping'siz, satrni qabul qilmaydi).enumJavaScript'ga kod qo'shadi (var+ IIFE). Node type stripping uni bajarmaydi,erasableSyntaxOnlyesaTS1294beradi.- Sonli enum'ga istalgan
numbero'tadi — tur tuzog'i.const enum— obyektsiz, lekin alohida o'giriladigan vositalar bilan xavfli. - Muqobil: faqat tur kerak bo'lsa — literal union; qiymatlar ro'yxati ham kerak bo'lsa —
as constobyekt va(typeof X)[keyof typeof X]. switch+nevervasatisfies Record<Union, V>— yangi holat qo'shilganda unutilgan joylarnitscko'rsatadi.
Keyingi dars: Generics: turni parametr qilish — bitta funksiya turli turlar bilan ishlaydi va tur ma'lumotini yo'qotmaydi: first<T>(items: T[]): T.
Manbalar
- TypeScript Handbook: "Enums" (Numeric, String, Reverse mappings, const enums, Objects vs Enums) — typescriptlang.org/docs/handbook/enums.html
- TypeScript 5.8 Release Notes: "The
--erasableSyntaxOnlyOption" — typescriptlang.org/docs/handbook/release-notes/typescript-5-8.html - Node.js hujjatlari: "Modules: TypeScript" (Type stripping, unsupported features) — nodejs.org/api/typescript.html
- TypeScript Handbook: "Everyday Types" (Literal Types) — typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!