Union turlar — | operatori, narrowing bilan ishlash

~20 daq · TypeScript · Asosiy Turlar

Foydalanuvchining ID si qanday saqlanishi haqida bahslashasiz. Backend number ishlatadi, lekin URL dan kelganda string bo'ladi. Funksiya ikkala holatni ham qabul qilishi kerak.

JavaScript da bu muammo yo'q — istalgan narsani bersavering. TypeScript da esa aniq belgilanishi shart. Bu holat uchun — Union tur.


Union tur nima?

| (pipe) operatori bilan ikki yoki undan ko'p tur birlashtiriladi. "Bu yoki bu" degan ma'no:

type Id = number | string;

function topish(id: number | string): void {
  console.log(id);
}

topish(42);      // ✅ — number
topish("abc-1"); // ✅ — string
topish(true);    // ❌ — boolean ruxsat yo'q

Hayotiy o'xshatma

Pochta qutisi. Ichiga xat ham keladi (qog'oz), to'lov kvitansiyasi ham (elektron). Ikki xil narsa — lekin ikkalasi ham "pochta qutisi uchun". Union tur — o'sha pochta qutisi: har xil narsalarni qabul qiladi, lekin faqat belgilanganlari.


Narrowing — qaysi tur ekanini aniqlash

Union turda ishlaganda TypeScript "bu number mi yoki string mi?" deb so'raydi. Tur aniqlanmasa — ikkala turda ham mavjud bo'lgan metodlar ishlaydi, boshqalar emas.

function uzunlik(qiymat: number | string): number {
  return qiymat.length;
  // ❌ — number da .length yo'q
}

Yechim — narrowing: qaysi tur ekanini tekshirib, shungacha kirisish:

function uzunlik(qiymat: number | string): number {
  if (typeof qiymat === "string") {
    return qiymat.length; // ✅ — bu blokda qiymat aniq string
  }
  return qiymat.toString().length; // ✅ — bu blokda qiymat aniq number
}

if bloki ichida TypeScript turni biladi — bu type narrowing. Faqat shu turda mavjud metodlarni ruxsat beradi.


typeof bilan narrowing

typeof — JavaScript ning o'zi:

Tekshiruv Natija
typeof x === "string" string
typeof x === "number" number
typeof x === "boolean" boolean
typeof x === "function" function
function hisoblash(a: number | string, b: number | string) {
  if (typeof a === "number" && typeof b === "number") {
    return a + b; // son qo'shish
  }
  return `${a}${b}`; // matn birlashtirish
}

Ko'p turli union

Ikki bilan cheklanmaydi:

type Natija = "muvaffaqiyat" | "xato" | "kutilmoqda" | "bekor_qilindi";

function holatChiqar(holat: Natija): string {
  if (holat === "muvaffaqiyat") return "✅ Tayyor";
  if (holat === "xato")         return "❌ Xato";
  if (holat === "kutilmoqda")   return "⏳ Kutilmoqda";
  return "🚫 Bekor qilindi";
}

Bu — literal union (aniq qiymatlar to'plami). Funksiyani faqat belgilangan to'rtta qiymatdan biri bilan chaqirish mumkin.


Union va null

Union ning eng keng tarqalgan ishlatilishi — nullable tur:

type FoydalanuvchiId = number | null;

function topish(id: FoydalanuvchiId): string {
  if (id === null) return "Foydalanuvchi topilmadi";
  return `Foydalanuvchi ID: ${id}`;
}

null bo'lishi mumkin bo'lgan qiymatlarni T | null bilan belgilash — TypeScript ning asosiy qoidalaridan biri.


Ob'ekt union — discriminated union

Hayotiy o'xshatma

Pochta orqali ikki xil narsa kelishi mumkin: xat yoki paket. Xatda "jo'natuvchi manzili" bor, paketda "og'irlik" bor. Har birini ochishdan oldin — bu xatmi yoki paketmi ekanini bilish kerak.

Har ob'ektda "tur belgisi" (kind, type, tag) bo'lsa — TypeScript uni ishonchli ajratadi:

type Xat   = { tur: "xat";   mazmun: string };
type Paket = { tur: "paket"; ogirlik: number };

type Pochta = Xat | Paket;

function qayta(pochta: Pochta): string {
  if (pochta.tur === "xat") {
    return pochta.mazmun; // ✅ — Xat, .mazmun mavjud
  }
  return `${pochta.ogirlik} kg`; // ✅ — Paket, .ogirlik mavjud
}

pochta.tur orqali TypeScript qaysi ob'ekt ekanini aniq biladi — faqat shu turda mavjud xususiyatlarga kirishga ruxsat beradi.


Tez-tez uchraydigan xatolar

Narrowingsiz union xususiyatiga kirishga urinish:

function boshliqHarfi(x: number | string): string {
  return x.toUpperCase();
  // ❌ — number da toUpperCase() yo'q
}

// ✅
function boshliqHarfi(x: number | string): string {
  if (typeof x === "string") return x.toUpperCase();
  return x.toString();
}

Discriminated union da tur xususiyatini unutish:

type Muvaffaqiyat = { natija: string };
type Xato         = { xabar: string };
type Javob        = Muvaffaqiyat | Xato;

function qayta(j: Javob) {
  console.log(j.natija);
  // ❌ — Xato da .natija yo'q, TypeScript bilmaydi qaysi tur
}

Discriminated union da har ob'ektga tur: "..." kabi belgisi bo'lishi shart.


Xulosa

| operatori — ikki yoki undan ko'p tur. "Bu yoki bu" degan ma'no.

Union bilan ishlashda narrowing kerak: typeof, === null, yoki ob'ektlarda tur belgisi orqali qaysi tur ekanini aniqlash.

Eng keng tarqalgan holat: T | null — qiymat bo'lishi ham, bo'lmasligi ham mumkin.

Discriminated union — har ob'ektda tur belgisi, TypeScript ularni ishonchli ajratadi.


Keyingi dars

13-dars: Intersection turlar — & operatori, mixin pattern