IlmHamroh
JavaScript Full-stack/15-qism. TypeScript7/47-dars18 daqiqa
Mundarija (31)

TypeScript union va literal turlar: "faol" | "bajarilgan" va as const

Qisqacha: Union (birlashma) — "bu yoki u" turi: string | number — satr yoki son. Uni literal turlar bilan birlashtirsangiz, qiymat faqat bir nechta aniq variantdan biri bo'ladi: type Filter = "hammasi" | "faol" | "bajarilgan". Imlo xatosi ("bajarlgan") kod ishga tushmasdan ushlanadi. Ro'yxat va turni bir joyda saqlash uchun: const FILTERS = [...] as const va type Filter = (typeof FILTERS)[number].

Bu darsda

  • A | B turini yozasiz va union bilan nima qilish mumkinligini bilasiz.
  • Satr va son literallaridan "faqat shu variantlar" degan tur yasaysiz.
  • Literal tur qachon string ga kengayishini (widening) va uni qanday to'xtatishni tushuntira olasiz.
  • Massivdan union yasaysiz: ro'yxat ham, tur ham bitta joyda.
  • includes tuzog'ini va uning to'g'ri yechimini bilasiz.

Oldin bilishingiz kerak: type va interface, Tur annotatsiyasi va tur chiqarish (literal tur), Massiv va tuple turlari (as const).

1. Nega bu kerak?

O'tgan darsda type Size = "kichik" | "o'rta" | "katta" ni ko'rdik va "bu union, keyingi darsda" dedik. Mana o'sha dars.

vazifalar ilovasida filtr bor: "hammasi", "faol", "bajarilgan". Sardor «Bahor» uchun shunga o'xshash buyurtmalar ekranini yozdi:

js
const orders = [
  { dish: "Osh", done: true },
  { dish: "Manti", done: false },
];

function visible(filter) {
  if (filter === "faol") return orders.filter((o) => !o.done);
  if (filter === "bajarlgan") return orders.filter((o) => o.done);
  return orders;
}

console.log(visible("bajarilgan").length); // 2

"Bajarilgan" tugmasi bosilganda ikkala buyurtma ham chiqdi — tayyori ham, tayyor emasi ham. Funksiyada "bajarlgan" deb yozilgan (bitta i tushib qolgan). Satrlar teng emas, shuning uchun kod oxirgi return orders ga yetdi. Xato xabari yo'q.

JavaScript uchun filter — oddiy satr, istalgan satr. Lekin bizning ilovada u faqat uchta qiymatdan biri bo'lishi mumkin. Bu bilim hozir faqat Sardorning boshida. Bugun uni turga yozamiz.

2. Union: "bu yoki u"

2.1 string | number

Union (birlashma) — bir nechta turdan biri bo'la oladigan tur. Ular | ("yoki") bilan yoziladi. Kundalik o'xshatish — kassada to'lov: naqd yoki karta. Ikkalasi ham qabul qilinadi, uchinchisi (masalan, kupon) — yo'q.

ts
let tableId: string | number;
tableId = 7;
tableId = "VIP-2";
console.log(tableId); // VIP-2

Stol raqami oddiy zalda son, VIP xonada esa "VIP-2" kabi satr. Ikkalasi ham to'g'ri. true yoki massiv berib bo'lmaydi.

JSDoc darsida union'ni @param {string | number} shaklida ko'rgansiz — yozuv aynan o'sha.

2.2 Union bilan nima qilish mumkin?

Faqat ikkala turda ham bor narsani:

ts
function label(id: string | number) {
  return id.toUpperCase();
}

Kompilyator:

text
TS2339: Property 'toUpperCase' does not exist on type 'string | number'.
  Property 'toUpperCase' does not exist on type 'number'.

Tarjimasi: "string | number turida toUpperCase xususiyati yo'q. Aniqrog'i, number turida yo'q". Ikkinchi qator aybdorni aytadi: union'ning bir a'zosi. id son bo'lsa, toUpperCase yo'q — kod yiqilardi.

Qaysi biri ekanini tekshirsangiz, TypeScript tekshiruvdan keyin turni toraytiradi:

ts
function label(id: string | number) {
  if (typeof id === "string") {
    return id.toUpperCase();
  }
  return `Stol ${id}`;
}

console.log(label("vip-2"), label(7)); // VIP-2 Stol 7

if ichida id — string, undan keyin esa — number. Bu toraytirish (narrowing); uning hamma usullari — Narrowing: turni toraytirish darsida. Bugun bitta narsani eslab qoling: union qiymatini ishlatishdan oldin, odatda, uning qaysi a'zo ekanini aniqlaysiz.

2.3 Qiymat berilganda tur o'zi toraydi

ts
let tableId: string | number = 7;
console.log(tableId.toFixed(1)); // 7.0

tableId — string | number deb e'lon qilingan, lekin TypeScript oxirgi berilgan qiymatni kuzatadi: hozir u 7, son. Shuning uchun toFixed ruxsat. tableId = "VIP-2" dan keyin esa satr bo'ladi. E'lon qilingan tur — "nima bo'lishi mumkin", joriy tur — "hozir nima".

Tekshirib ko'ring: function len(x: string | string[]) { return x.length; } — xato bormi?

Javob

Xato yo'q. length satrda ham, massivda ham bor — ikkala a'zoning umumiy xususiyati. Union bilan umumiy narsalarni tekshirmasdan ishlatish mumkin. Natija turi ham number — ikkalasida ham length son.

3. Literal turlar va ularning union'i

3.1 Bitta qiymatdan iborat tur

Tur chiqarish darsida literal tur bilan tanishgan edik: const city = "Toshkent" ning turi — "Toshkent", faqat shu satr. Literal turni o'zingiz ham yozishingiz mumkin, lekin bittasi yolg'iz foydasiz: let mode: "tez" ga faqat "tez" beriladi. Kuchi — union'da.

3.2 "Faqat shu uch qiymatdan biri"

ts
type Filter = "hammasi" | "faol" | "bajarilgan";

let current: Filter = "faol";
current = "bajarilgan";
console.log(current); // bajarilgan

Filter — uchta literal turning union'i: qiymat faqat shu uch satrdan biri. Endi Sardorning xatosi:

ts
type Filter = "hammasi" | "faol" | "bajarilgan";

let current: Filter = "bajarlgan";

Kompilyator:

text
TS2820: Type '"bajarlgan"' is not assignable to type 'Filter'. Did you mean '"bajarilgan"'?

Tarjimasi: ""bajarlgan" turini Filter ga berib bo'lmaydi. "bajarilgan" ni nazarda tutdingizmi?" TypeScript nafaqat xatoni topdi, balki to'g'ri variantni ham taklif qildi. Katta-kichik harf ham farq qiladi:

ts
type Filter = "hammasi" | "faol" | "bajarilgan";

function show(filter: Filter) {
  return filter;
}
show("Faol");

Kompilyator:

text
TS2345: Argument of type '"Faol"' is not assignable to parameter of type 'Filter'.

Muharrirda yana bir foyda bor: show(" deb yozishingiz bilan VS Code uchta variantni ro'yxat qilib taklif qiladi. Variantlarni yodlash shart emas.

3.3 Son va mantiqiy literallar

Literal faqat satr emas:

ts
type Rating = 1 | 2 | 3 | 4 | 5;
const review: Rating = 6;

Kompilyator:

text
TS2322: Type '6' is not assignable to type 'Rating'.

TypeScript aytyapti: «6 turini Rating turiga berib bo'lmaydi». Bu yerda 6 — literal tur: faqat 6 sonining o'zi, u esa ruxsat etilgan beshtalikda yo'q.

Mehmon bahosi 1 dan 5 gacha. 6 — xato. Qiziq fakt: boolean turining o'zi ham union — true | false. TypeScript uni hover'da boolean deb qisqa ko'rsatadi.

3.4 Xabarlardagi tartib

Union'da a'zolarning tartibi ahamiyatsiz: "a" | "b" va "b" | "a" — bir xil tur. TypeScript 7 xabarlarda ularni o'z tartibida chiqarishi mumkin. Masalan, "yangi" | "tayyor" | "berildi" xabarda "berildi" | "tayyor" | "yangi" bo'lib ko'rinadi. Hayron bo'lmang — tur o'sha.

Tekshirib ko'ring: type Size = "kichik" | "o'rta" | "katta"; va const s: Size = "O'rta"; — xato bormi? Nega?

Javob

Xato bor — TS2322. Literal tur aynan bitta satr: "o'rta" va "O'rta" — boshqa-boshqa satrlar (birinchi harf katta). TypeScript JavaScript'dagi === kabi solishtiradi: harfma-harf.

4. Kengayish: literal qachon string bo'lib qoladi

4.1 let va obyekt xususiyati

Tur chiqarish darsidagi qoida endi amalda kerak bo'ladi: let va obyekt ichidagi literal kengayadi (widening) — "faol" → string.

ts
type Status = "yangi" | "tayyor";

function setStatus(status: Status) {
  return status;
}

const order = { dish: "Osh", status: "yangi" };
setStatus(order.status);

Kompilyator:

text
TS2345: Argument of type 'string' is not assignable to parameter of type 'Status'.

Qiymat — aynan "yangi", xabar esa string deydi. Nega? Obyekt xususiyatini keyin o'zgartirish mumkin (order.status = "boshqa"), shuning uchun TypeScript status ga keng tur berdi: string. string esa Status ga mos emas — har satr ham holat emas.

4.2 Uch tuzatish

ts
type Status = "yangi" | "tayyor";

function setStatus(status: Status) {
  return status;
}

// 1) obyektga tur yozish
const a: { dish: string; status: Status } = {
  dish: "Osh",
  status: "yangi",
};
// 2) faqat bitta qiymatni "qotirish"
const b = { dish: "Manti", status: "yangi" as const };
// 3) butun obyektni qotirish (hammasi readonly bo'ladi)
const c = { dish: "Lag'mon", status: "tayyor" } as const;

console.log(setStatus(a.status), setStatus(b.status)); // yangi yangi
console.log(setStatus(c.status)); // tayyor

tsc --declaration bilan uchala o'zgaruvchining turini ko'rdik (muharrir hover'da xuddi shuni ko'rsatadi):

Kod Chiqarilgan tur
{ dish: "Osh", status: "yangi" } { dish: string; status: string; }
{ …, status: "yangi" as const } { dish: string; status: "yangi"; }
{ … } as const { readonly dish: "Lag'mon"; readonly status: "tayyor"; }

Qaysi birini tanlash? Obyekt keyin o'zgaradigan bo'lsa (buyurtma holati "yangi" dan "tayyor" ga o'tadi) — birinchisi: tur yozish. Butunlay o'zgarmas sozlama bo'lsa — uchinchisi. as const ni massivlarda ko'rgan edik — obyektda ham xuddi shu ish qiladi: literal turlar va readonly.

flowchart TD
  A["Literal qiymat: "faol""] --> B{"Qayerda yozilgan?"}
  B -- "const x = …" --> L["Literal tur: "faol""]
  B -- "let x = …" --> S["Kengayadi: string"]
  B -- "obyekt yoki massiv ichida" --> S
  B -- "… as const" --> R["Literal + readonly"]
  B -- "tur yozilgan: x: Filter" --> F["Filter"]

Sxema bitta savol beradi: "qiymat keyin o'zgarishi mumkinmi?" Mumkin bo'lsa — TypeScript kengaytiradi. Siz aniq tur yozsangiz yoki as const desangiz — kengaytirmaydi.

Tekshirib ko'ring: let mode = "faol"; show(mode); (show(filter: Filter)) — xato bormi? let ni const ga almashtirsak-chi?

Javob

let bilan — TS2345: Argument of type 'string' is not assignable to parameter of type 'Filter'. — let mode kengaydi. const bilan — xato yo'q: const mode turi "faol", u Filter ning a'zosi. Uchinchi yo'l: let mode: Filter = "faol"; — let ham qoladi, tur ham aniq.

5. Ro'yxat va tur — bitta joyda

5.1 Ikki joyda yozish muammosi

Ko'pincha union'ning qiymatlari ishlash paytida ham kerak: tugmalar chizish, URL'dagi qiymatni tekshirish. Sodda yo'l — ikki marta yozish:

ts
type Filter = "hammasi" | "faol" | "bajarilgan";
const FILTERS = ["hammasi", "faol", "bajarilgan"];

Ertaga "arxiv" filtri qo'shiladi. Uni bir joyga yozib, ikkinchisini unutish oson. Tur va ro'yxat bir-biridan ajraladi.

5.2 as const dan union

Teskari yo'ldan boramiz: ro'yxatni bir marta yozamiz, turni undan chiqaramiz:

ts
const FILTERS = ["hammasi", "faol", "bajarilgan"] as const;
type Filter = (typeof FILTERS)[number];

const first: Filter = FILTERS[0];
console.log(FILTERS.length, first); // 3 hammasi

Bosqichma-bosqich o'qiymiz:

  1. as const — massiv o'zgarmas tuple bo'ldi: readonly ["hammasi", "faol", "bajarilgan"] (o'tgan darslardan).
  2. typeof FILTERS — tur joyida yozilgan typeof: "FILTERS o'zgaruvchisining turi". Bu JavaScript'dagi typeof emas (u satr qaytaradi). Tur joyida u TypeScript'ning operatori.
  3. [number] — "shu turdagi massivning istalgan raqamli indeksidagi element turi". Tuple'da bu — hamma elementlar turlarining union'i.

Natija: Filter = "hammasi" | "faol" | "bajarilgan". Endi "arxiv" ni faqat FILTERS ga qo'shasiz — tur o'zi yangilanadi. typeof va indeks bilan tur olishning hamma imkoniyatlari — keyof, typeof va indexed access darsida.

5.3 includes tuzog'i

URL'dan kelgan matn — oddiy string. Uni ro'yxatda bormi deb tekshiramiz:

ts
const FILTERS = ["hammasi", "faol", "bajarilgan"] as const;
type Filter = (typeof FILTERS)[number];

function parseFilter(text: string): Filter {
  if (FILTERS.includes(text)) {
    return text;
  }
  return "hammasi";
}

Kompilyator:

text
TS2345: Argument of type 'string' is not assignable to parameter of type '"bajarilgan" | "faol" | "hammasi"'.
TS2322: Type 'string' is not assignable to type '"bajarilgan" | "faol" | "hammasi"'.

TypeScript aytyapti: «string turidagi argumentni "bajarilgan" | "faol" | "hammasi" turidagi parametrga berib bo'lmaydi» va «string ni o'sha uchtalikka yozib bo'lmaydi». Ya'ni har qanday satr emas, faqat shu uch so'z kerak.

Ikki xato, ikkalasi ham kutilmagan:

  • includes o'z massivining element turini kutadi. FILTERS — Filter lar massivi, shuning uchun includes ham faqat Filter qabul qiladi. Bizda esa string. TypeScript'ning mantig'i: "satrlar massivida yo'q narsani qidirish — xato bo'lishi mumkin".
  • includes toraytirmaydi. true qaytgan bo'lsa ham, text string bo'lib qoladi va Filter sifatida qaytarib bo'lmaydi.

To'g'ri yo'l — find. U topilgan elementni qaytaradi, element turi esa — Filter:

ts
const FILTERS = ["hammasi", "faol", "bajarilgan"] as const;
type Filter = (typeof FILTERS)[number];

function parseFilter(text: string | null): Filter {
  return FILTERS.find((filter) => filter === text) ?? "hammasi";
}

console.log(parseFilter("faol")); // faol
console.log(parseFilter("bajarlgan")); // hammasi
console.log(parseFilter(null)); // hammasi

find — Filter | undefined qaytaradi: topilsa — ro'yxatdagi qiymat (aynan Filter turida), topilmasa — undefined. ?? esa undefined o'rniga standart filtrni qo'yadi. Parametr — string | null: brauzerdagi URLSearchParams.get() parametr yo'q bo'lsa null qaytaradi. Qiymat va tur bir vaqtda tekshirildi. vazifalar ning marshrut moduli null va undefined bilan xavfsiz ishlash qadamida aynan shu usulga o'tadi.

Tekshirib ko'ring: const SIZES = ["kichik", "katta"] as const; type Size = typeof SIZES; — const s: Size = "kichik" ishlaydimi?

Javob

Yo'q: TS2322: Type 'string' is not assignable to type 'readonly ["kichik", "katta"]'. typeof SIZES — massivning o'zi (tuple) turi, uning elementi emas. Element turi uchun oxiriga [number] qo'shiladi: type Size = (typeof SIZES)[number];.

6. TypeScript nimani ushlamaydi

Union — kompilyatsiya paytidagi va'da. Tashqaridan kelgan matn bu va'dani bilmaydi:

ts
type Filter = "hammasi" | "faol" | "bajarilgan";
const TITLES = {
  hammasi: "Hammasi",
  faol: "Faol",
  bajarilgan: "Bajarilgan",
};

const saved: Filter = JSON.parse('"arxiv"'); // eski versiyadan
console.log(TITLES[saved].toUpperCase());

tsc — xatosiz: JSON.parse — any, u Filter ga jim mos keladi. TITLES[saved] ning turi — string (uchala kalit ham bor). Node esa:

text
TypeError: Cannot read properties of undefined (reading 'toUpperCase')

localStorage dagi eski qiymat "arxiv" ilovaning yangi versiyasida yo'q. Tashqi qiymatni union'ga berishdan oldin tekshiring: yuqoridagi parseFilter aynan shuni qiladi. Server ma'lumotlarini tekshirish — API ma'lumotlarini tiplash darsida.

7. Ko'p uchraydigan xatolar

7.1 Qo'shtirnoqni unutish

ts
type Size = kichik | katta;

Kompilyator:

text
TS2304: Cannot find name 'kichik'.
TS2304: Cannot find name 'katta'.

Tarjimasi: "kichik nomini topib bo'lmadi". Qo'shtirnoqsiz kichik — tur nomi deb o'qiladi (MenuItem kabi), bunday tur esa yo'q. Tuzatish: type Size = "kichik" | "katta";.

7.2 | o'rniga ||

|| — JavaScript'ning "yoki" operatori, qiymatlar bilan ishlaydi. Turlarda — bitta |. Tuzatish: string | number.

7.3 Union'ni let ga berib, keyin kengayishdan hayron bo'lish

let filter = "faol" — string. Tuzatish: const yoki aniq tur: let filter: Filter = "faol".

7.4 typeof X va (typeof X)[number] ni adashtirish

Birinchisi — butun massiv turi, ikkinchisi — element turi. Tuzatish: union kerak bo'lsa — [number] bilan.

8. Mashqlar

1-mashq (oson): Turini ayting

ts
const PORTIONS = ["yarim", "to'liq"] as const;
type Portion = (typeof PORTIONS)[number];
let spice = "achchiq";
const level = 2;
const p: Portion = "yarim";
console.log(PORTIONS.length, spice, level, p); // 2 achchiq 2 yarim

let spice ning turi: [:string]. const level ning turi (literal): [:2]. Portion nechta a'zodan iborat: .

Yechim

spice — let, literal kengaydi: string. level — const, turi aynan 2. Portion — "yarim" | "to'liq", ikki a'zo: as const massivi elementlaridan yasalgan union.

2-mashq (o'rta): Kengayishni tuzating

Kod tsc dan o'tmaydi. Ikki xil yo'l bilan tuzating: (a) obyektga tur yozib, (b) as const bilan. Qaysi biri bu yerda to'g'riroq?

ts
type Payment = "naqd" | "karta" | "click";

function pay(sum: number, method: Payment) {
  return `${sum} so'm — ${method}`;
}

const bill = { sum: 70000, method: "karta" };
bill.method = "naqd";
console.log(pay(bill.sum, bill.method));

Kompilyator:

text
TS2345: Argument of type 'string' is not assignable to parameter of type 'Payment'.
Yechim

(a) — to'g'ri yo'l, chunki bill.method keyin o'zgaradi:

ts
type Payment = "naqd" | "karta" | "click";

function pay(sum: number, method: Payment) {
  return `${sum} so'm — ${method}`;
}

const bill: { sum: number; method: Payment } = {
  sum: 70000,
  method: "karta",
};
bill.method = "naqd";
console.log(pay(bill.sum, bill.method)); // 70000 so'm — naqd

(b) as const bilan esa ikkinchi qator buziladi:

ts
type Payment = "naqd" | "karta" | "click";

const bill = { sum: 70000, method: "karta" } as const;
bill.method = "naqd";

Kompilyator:

text
TS2540: Cannot assign to 'method' because it is a read-only property.

as const hammasini readonly qiladi — o'zgarmaydigan qiymatlar uchun. { method: "karta" as const } (faqat bitta qiymat) ham yordam bermaydi: unda method turi aynan "karta" bo'ladi va "naqd" ni yozib bo'lmaydi (TS2322). Qiymat o'zgaradigan bo'lsa — union'ni tur sifatida yozing.

3-mashq (qiyin): Amaliy tajriba — buyurtma holatlari

Mashq kurs/mashqlar/15/ papkasida. 07-union/order-status.ts faylini yarating. Birinchi variant JavaScript'dan "to'g'ridan-to'g'ri" ko'chirilgan:

ts
// 07-union/order-status.ts — «Bahor» buyurtma holatlari
export const STATUSES = [
  "yangi",
  "tayyorlanmoqda",
  "tayyor",
  "berildi",
] as const;
export type OrderStatus = (typeof STATUSES)[number];

const LABELS = {
  yangi: "Yangi buyurtma",
  tayyorlanmoqda: "Oshxonada",
  tayyor: "Olib keting",
};

export function parseStatus(text: string): OrderStatus {
  if (STATUSES.includes(text)) {
    return text;
  }
  throw new RangeError(`Noma'lum holat: ${text}`);
}

export function statusLabel(status: OrderStatus): string {
  return LABELS[status];
}
  1. npx tsc --pretty false ni ishga tushiring — uchta xato chiqadi. Har birini o'qing: qaysi biri «includes tuzog'i», qaysi biri yangi?
  2. Uchala xatoni tuzating. parseStatus begona matnda RangeError tashlasin.
  3. nextStatus(status) qo'shing: keyingi holat, oxirgisidan keyin — o'zi. Ishora: STATUSES.indexOf(status) + 1 — keyingi indeks. Mashqlar papkasida noUncheckedIndexedAccess yoqilgan — indeks natijasi OrderStatus | undefined, uni ?? bilan yoping.
  4. 07-union/order-status.test.ts da testlar yozing: to'g'ri va begona matn (katta harfli ham), holatlar zanjiri, har holatning yozuvi borligi.
Yechim

1-qadamda tsc 7.0.2 shunday dedi:

text
07-union/order-status.ts(17,25): error TS2345: Argument of type 'string' is not assignable to parameter of type '"berildi" | "tayyor" | "tayyorlanmoqda" | "yangi"'.
07-union/order-status.ts(18,5): error TS2322: Type 'string' is not assignable to type '"berildi" | "tayyor" | "tayyorlanmoqda" | "yangi"'.
07-union/order-status.ts(24,10): error TS7053: Element implicitly has an 'any' type because expression of type '"berildi" | "tayyor" | "tayyorlanmoqda" | "yangi"' can't be used to index type '{ yangi: string; tayyorlanmoqda: string; tayyor: string; }'.
  Property 'berildi' does not exist on type '{ yangi: string; tayyorlanmoqda: string; tayyor: string; }'.

Birinchi ikkitasi — «includes tuzog'i». Uchinchisi yangi va juda foydali: "berildi xususiyati LABELS da yo'q". LABELS[status] — status to'rt qiymatdan biri, LABELS da esa faqat uchta kalit. JavaScript'da "berildi" holatidagi buyurtma ekranda undefined yozuvi bilan chiqardi. Union ro'yxat va yozuvlar jadvalini bir-biriga bog'ladi: yangi holat qo'shilsa, tsc yozuvi yo'qligini darhol aytadi. (TS7053 va Record bilan bunday jadvallarni yozish — Index signature va Record darsida.)

ts
// 07-union/order-status.ts — «Bahor» buyurtma holatlari
export const STATUSES = [
  "yangi",
  "tayyorlanmoqda",
  "tayyor",
  "berildi",
] as const;
export type OrderStatus = (typeof STATUSES)[number];

const LABELS = {
  yangi: "Yangi buyurtma",
  tayyorlanmoqda: "Oshxonada",
  tayyor: "Olib keting",
  berildi: "Berildi",
};

// Tashqaridan kelgan matn — oq ro'yxatdan; find topganini
// OrderStatus turida qaytaradi, topmasa — undefined
export function parseStatus(text: string): OrderStatus {
  const found = STATUSES.find((status) => status === text);
  if (found === undefined) {
    throw new RangeError(`Noma'lum holat: ${text}`);
  }
  return found;
}

// Keyingi holat; oxirgisidan keyin — o'zi
export function nextStatus(status: OrderStatus): OrderStatus {
  const next = STATUSES[STATUSES.indexOf(status) + 1];
  return next ?? status;
}

export function statusLabel(status: OrderStatus): string {
  return LABELS[status];
}

if (found === undefined) dan keyin found — OrderStatus: undefined chiqarib tashlandi. nextStatus da "berildi" ning indeksi 3, STATUSES[4] — undefined, demak holat o'zgarmaydi.

ts
// 07-union/order-status.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import {
  STATUSES,
  parseStatus,
  nextStatus,
  statusLabel,
} from "./order-status.ts";

test("parseStatus: ro'yxatdagi matn", () => {
  assert.equal(parseStatus("tayyor"), "tayyor");
});

test("parseStatus: begona va katta harfli matn — RangeError", () => {
  assert.throws(() => parseStatus("bekor"), RangeError);
  assert.throws(() => parseStatus("Tayyor"), RangeError);
});

test("nextStatus: zanjir va oxirgi holat", () => {
  assert.equal(nextStatus("yangi"), "tayyorlanmoqda");
  assert.equal(nextStatus("tayyor"), "berildi");
  assert.equal(nextStatus("berildi"), "berildi");
});

test("statusLabel: har holatning yozuvi bor", () => {
  for (const status of STATUSES) {
    assert.notEqual(statusLabel(status), undefined);
  }
  assert.equal(statusLabel("tayyor"), "Olib keting");
});

Testda nextStatus("bekor") deb yozib ko'ring — tsc TS2345 beradi: testlar ham turlar bilan tekshiriladi. npx tsc --pretty false — chiqishsiz. node --test 07-union/order-status.test.ts — bizda (Node 24.21.0):

text
✔ parseStatus: ro'yxatdagi matn (1.8442ms)
✔ parseStatus: begona va katta harfli matn — RangeError (0.9695ms)
✔ nextStatus: zanjir va oxirgi holat (0.2975ms)
✔ statusLabel: har holatning yozuvi bor (0.391ms)
ℹ tests 4
ℹ suites 0
ℹ pass 4
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 259.1104

XATOLAR.md ga yangi xabarlarni qo'shing: TS2820, TS2304, TS7053. Keyin kurs/mashqlar papkasidan:

bash
git add 15/07-union 15/XATOLAR.md
git commit -m "15/07: order-status.ts — literal union, as const, find"

Oldinga qarab: Vazifalar qadami. vazifalar da hali hamma filtr, saralash va xato kodlari oddiy string. Ruxsat etilgan qiymatlar faqat izohda yozilgan: @param {string} filtr "hammasi" | "faol" | "bajarilgan". Discriminated union va to'liqlik tekshiruvi qadamida turlar.ts ga Filtr, Saralash, TarmoqHolati va ikki xato kodi turi union bo'lib qo'shiladi, izohdagi ro'yxatlar esa turga aylanadi.

9. Real ishda

  • Holatlar va rejimlar — union'ning eng ko'p joyi: so'rov holati "idle" | "loading" | "error", tugma ko'rinishi "primary" | "danger", HTTP metodi "GET" | "POST". Kutubxonalarning turlari ham shunday: fetch ning RequestInit idagi mode — "cors" | "no-cors" | "navigate" | "same-origin".
  • Komponent xususiyatlari (React, 17-qismdan) — size: "sm" | "md" | "lg". Noto'g'ri qiymat bilan komponentni ishlatsangiz, muharrir darhol qizil chiziq tortadi.
  • as const ro'yxatlar — ruxsat etilgan qiymatlarning "yagona manbai": undan ham tur, ham <select> variantlari, ham tekshiruv yasaladi.
  • Intervyu: "Union va literal turlar nima?", "Nega let x = "a" ning turi string?", "as const nima qiladi?" — odatiy savollar.

Xulosa

  • A | B — "bu yoki u". Union bilan faqat umumiy narsalarni tekshirmasdan ishlatish mumkin, qolganiga — toraytirish.
  • Literal turlar union'i — "faqat shu variantlar": "hammasi" | "faol" | "bajarilgan". Imlo (TS2820) va katta-kichik harf xatolari ushlanadi.
  • let va obyekt ichidagi literal string ga kengayadi. To'xtatish: tur yozish (o'zgaradigan qiymat) yoki as const (o'zgarmas).
  • Ro'yxat va tur bir joyda: const X = [...] as const; type T = (typeof X)[number];.
  • includes satrni toraytirmaydi va string ni qabul qilmaydi — find(...) ?? standart ishlating.

Keyingi dars: any, unknown, never, void va object — "hamma narsa", "noma'lum", "hech qachon" va "hech narsa qaytarmaydi" degan maxsus turlar.

Manbalar

  • TypeScript Handbook: "Everyday Types" → Union Types, Literal Types, Literal Inference — typescriptlang.org/docs/handbook/2/everyday-types.html#union-types
  • TypeScript Handbook: "Typeof Type Operator", "Indexed Access Types" — typescriptlang.org/docs/handbook/2/typeof-types.html
  • TypeScript Release Notes 3.4 (const assertions) — typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html
  • MDN: URLSearchParams.get() — developer.mozilla.org/docs/Web/API/URLSearchParams/get
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
TypeScript union va literal turlar: "faol" | "bajarilgan" va as const — IlmHamroh