6-bo‘lim

Union va intersection turlari

Bir nechta turni birlashtirish, ajratuvchi maydon, never bilan to'liqlik tekshiruvi va ziddiyatli kesishma.

🕑 28 daqiqa o‘qish 📄 954 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Union: yo u, yo bu
  2. Union ustida faqat umumiy amallar
  3. Literal union
  4. Obyekt turlarining unioni
  5. Ajratuvchi maydon
  6. never bilan to'liqlik tekshiruvi
  7. Massiv tuzog'i
  8. Intersection: ikkalasi ham
  9. Ziddiyatli kesishma
  10. Yo'nalish
  11. null bilan union
  12. Xulosa

Hozirgacha har bir qiymatning bitta turi bor edi. Amalda esa qiymat "yo shu, yo bu" bo'ladi: id - son yoki satr, to'lov - naqd yoki karta.

Buning uchun ikkita amal bor: | (union) va & (intersection).

Union: yo u, yo bu #

TS
let id: string | number;

id = 101;
console.log(id);

id = "A-101";
console.log(id);
Terminal
tsx src/union.ts
Natija
101
A-101

Ikkalasidan tashqarisi o'tmaydi:

TS
let id: string | number;
id = true;
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/union2.ts(2,1): error TS2322: Type 'boolean' is not assignable to
type 'string | number'.

Union ustida faqat umumiy amallar #

Bu union bilan ishlashdagi birinchi to'siq:

TS
function chop(id: string | number): void {
  console.log(id.toString());
  console.log(id.toUpperCase());
}
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/umumiy.ts(3,18): error TS2339: Property 'toUpperCase' does not exist
on type 'string | number'.
  Property 'toUpperCase' does not exist on type 'number'.

toString() ikkalasida ham bor - ruxsat. toUpperCase() faqat satrda bor - taqiq. Xabarning ikkinchi qatori aynan qaysi a'zoda yo'qligini aytadi.

Yechim - toraytirish:

TS
function chop(id: string | number): string {
  if (typeof id === "string") return id.toUpperCase();
  return id.toFixed(0);
}

console.log(chop("a-101"));
console.log(chop(101.7));
Terminal
tsx src/torayt.ts
Natija
A-101
102

if ichida id - string, tashqarisida number. TypeScript oqimni kuzatib turadi. 7-bob to'liq shu mavzuga bag'ishlangan.

Literal union #

Union ning eng foydali ko'rinishi - aniq qiymatlar ro'yxati:

TS
type Daraja = "boshlangich" | "orta" | "yuqori";

const d: Daraja = "orta";
console.log(d);
Terminal
tsx src/literal.ts
Natija
orta
TS
type Daraja = "boshlangich" | "orta" | "yuqori";
const d: Daraja = "qiyin";
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/literal2.ts(2,7): error TS2322: Type '"qiyin"' is not assignable to
type 'Daraja'.
Literal union - enum o'rniga

Ko'p hollarda enum shart emas:

YozuvIsh vaqtidagi kodQiymati
type D = "a" | "b"Yo'q"a"
enum D { A, B }Bor - obyekt0

Literal union kompilyatsiyadan keyin butunlay yo'qoladi va JSON bilan to'g'ridan-to'g'ri mos tushadi. enum ni 14-bobda solishtiramiz.

Obyekt turlarining unioni #

TS
type Naqd = { usul: "naqd"; miqdor: number };
type Karta = { usul: "karta"; miqdor: number; raqam: string };
type Tolov = Naqd | Karta;

function chop(t: Tolov): void {
  console.log(t.usul, t.miqdor);
  console.log(t.raqam);
}
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/tolov.ts(7,17): error TS2339: Property 'raqam' does not exist on type
'Tolov'.
  Property 'raqam' does not exist on type 'Naqd'.

Bu yerda ko'pchilik adashadi: union obyektning maydonlarini qo'shmaydi, kamaytiradi. Faqat har ikkala a'zoda ham bor maydonga murojaat qilish mumkin.

Obyekt turlarida: nomi bir xil, ta'siri teskari Naqd usul: "naqd" miqdor: number Karta usul: "karta" miqdor: number raqam: string Naqd | Karta usul miqdor 2 ta maydon - KAMROQ faqat ikkalasida borlari Naqd & Karta usul miqdor raqam 3 ta maydon - KO'PROQ hammasi birga lekin usul turi ziddiyatli usul: never Eslab qolish Qiymatlar to'plami uchun: | kengaytiradi & toraytiradi Maydonlar uchun esa aynan teskari Sabab: qiymat kamroq maydonga kafolat bersa, u ko'proq qiymatga mos keladi. Union bilan ishlash uchun ajratuvchi maydon qo'ying.
Union maydonlarni kamaytiradi, intersection ko'paytiradi

Ajratuvchi maydon #

Yechim - har bir a'zoda bir xil nomli, turli literal qiymatli maydon bo'lishi:

TS
type Naqd = { usul: "naqd"; miqdor: number };
type Karta = { usul: "karta"; miqdor: number; raqam: string };
type Tolov = Naqd | Karta;

function chop(t: Tolov): string {
  if (t.usul === "karta") return `karta ${t.raqam}`;
  return `naqd ${t.miqdor}`;
}

console.log(chop({ usul: "naqd", miqdor: 12000 }));
console.log(chop({ usul: "karta", miqdor: 50000, raqam: "8600" }));
Terminal
tsx src/tolov2.ts
Natija
naqd 12000
karta 8600

t.usul === "karta" ni ko'rgach, TypeScript t ni Karta deb biladi va t.raqam ochiladi. Bunday union ajratilgan union (discriminated union) deyiladi va u TypeScript dagi eng kuchli naqshlardan biri.

never bilan to'liqlik tekshiruvi #

Unionga yangi a'zo qo'shganda, uni ishlatadigan barcha joylarni topish kerak. never buni kompilyatorga yuklaydi:

TS
type Naqd = { usul: "naqd" };
type Karta = { usul: "karta" };
type Payme = { usul: "payme" };
type Tolov = Naqd | Karta | Payme;

function nomi(t: Tolov): string {
  switch (t.usul) {
    case "naqd":
      return "Naqd pul";
    case "karta":
      return "Bank kartasi";
    default: {
      const qolgan: never = t;
      return qolgan;
    }
  }
}
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/toliq.ts(13,13): error TS2322: Type 'Payme' is not assignable to type
'never'.

Xabar aynan qaysi a'zo unutilganini aytdi: Payme.

Barcha holatlar qamralgan bo'lsa, default ga hech qachon yetib borilmaydi va t ning turi never bo'ladi - xato chiqmaydi. Bitta holat unutilsa - xato darhol paydo bo'ladi.

Bu naqshni yodda tuting

switch ning default shoxiga const qolgan: never = t; yozib qo'ying. Endi unionga yangi a'zo qo'shsangiz, kompilyator o'zi sizni tuzatilishi kerak bo'lgan har bir joyga olib boradi.

Bu - "unutdim" degan xatolarni butunlay yo'q qiladigan kam sonli usullardan biri.

Massiv tuzog'i #

TS
function qosh(royxat: string[] | number[]): void {
  royxat.push("Olma");
}
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/massiv.ts(2,15): error TS2345: Argument of type '"Olma"' is not
assignable to parameter of type 'never'.

never qayerdan chiqdi? royxat yo string[], yo number[]. push ikkalasida ham bor, lekin biri string, ikkinchisi number kutadi. Ikkalasiga ham mos keladigan qiymat yo'q - shuning uchun never.

Odatda kerakli narsa boshqasi:

TS
const aralash: (string | number)[] = ["Olma", 12000];
aralash.push("Anor");
aralash.push(30000);
console.log(aralash.length, aralash.join(", "));
Terminal
tsx src/massiv2.ts
Natija
4 Olma, 12000, Anor, 30000
YozuvMa'nosi
string[] | number[]Butun massiv yo satrli, yo sonli
(string | number)[]Har bir element satr yoki son

Qavsni tushirib qoldirish - ko'p uchraydigan xato.

Intersection: ikkalasi ham #

TS
type Shaxs = { nomi: string; yosh: number };
type Xodim = { lavozim: string; maosh: number };
type XodimShaxs = Shaxs & Xodim;

const x: XodimShaxs = {
  nomi: "Husanboy",
  yosh: 25,
  lavozim: "dasturchi",
  maosh: 9000000,
};

console.log(x.nomi, x.lavozim, x.maosh);
Terminal
tsx src/kesish.ts
Natija
Husanboy dasturchi 9000000

Bittasining maydonini tushirib qoldirsak:

TS
type Shaxs = { nomi: string; yosh: number };
type Xodim = { lavozim: string; maosh: number };

const x: Shaxs & Xodim = { nomi: "Husanboy", yosh: 25 };
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/kesish2.ts(4,7): error TS2322: Type '{ nomi: string; yosh: number; }'
is not assignable to type 'Shaxs & Xodim'.
  Type '{ nomi: string; yosh: number; }' is missing the following
properties from type 'Xodim': lavozim, maosh

Ziddiyatli kesishma #

Ikki turda bir xil nomli, turli turdagi maydon bo'lsa nima bo'ladi?

TS
type A = { id: number };
type B = { id: string };
type C = A & B;

const c: C = { id: 1 };
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/zid.ts(5,16): error TS2322: Type 'number' is not assignable to type
'never'.

C["id"] ning turi - never. Ya'ni "bir vaqtning o'zida ham son, ham satr bo'lgan qiymat" mavjud emas.

E'tibor bering: type C = A & B qatori xato bermadi. Tur bemalol yaratildi; muammo faqat unga qiymat berishga urinilganda ko'rindi.

never ning o'zi juda g'alati tur - unga hech narsa berib bo'lmaydi, lekin uni hamma joyga berish mumkin:

TS
type A = { id: number };
type B = { id: string };
type C = A & B;

declare const c: C;

const son: number = c.id;
const satr: string = c.id;

c.id.toFixed(0);
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/zid2.ts(10,6): error TS2339: Property 'toFixed' does not exist on
type 'never'.

c.id ni ham number ga, ham string ga berish mumkin bo'ldi

  • xato yo'q. Lekin uning ustida hech qanday amal bajarib

bo'lmaydi. never - "bunday qiymat bo'lishi mumkin emas" degani, shuning uchun u har qanday va'daga rozi.

Ziddiyatli kesishma jim yaratiladi

A & B ni e'lon qilganda xato chiqmagani sizni chalg'itmasin. Agar turlar mos kelmasa, natija never maydonli, hech qachon to'ldirib bo'lmaydigan tur bo'ladi.

Bu ko'pincha ikkita kutubxonaning turlarini qo'shganda yuz beradi. Shubhangiz bo'lsa, maydonni ataylab ishlatib ko'ring - never darhol chiqadi.

Yo'nalish #

Kesishma turidagi qiymat o'z qismlariga mos keladi:

TS
type Shaxs = { nomi: string };
type Xodim = { lavozim: string };

const ikkisi: Shaxs & Xodim = { nomi: "Husanboy", lavozim: "dasturchi" };
const faqatShaxs: Shaxs = ikkisi;

const birortasi: Shaxs | Xodim = { nomi: "Ali" };

console.log(faqatShaxs.nomi, "|", ikkisi.lavozim);
console.log("nomi" in birortasi ? birortasi.nomi : "nomsiz");
Terminal
tsx src/yonalish.ts
Natija
Husanboy | dasturchi
Ali

Shaxs & Xodim ni Shaxs ga berish mumkin - unda Shaxs talab qilgan hamma narsa bor. Teskarisi esa yo'q.

in operatori - unionni toraytirishning yana bir yo'li.

null bilan union #

TS
function narxi(nomi: string): number | null {
  return nomi === "Olma" ? 12000 : null;
}

const n = narxi("Anor");
console.log(n.toFixed(0));
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/nul.ts(6,13): error TS18047: 'n' is possibly 'null'.

"Topilmadi" ni null bilan qaytarish - keng tarqalgan naqsh. strictNullChecks uni tekshirishga majbur qiladi:

TS
function narxi(nomi: string): number | null {
  return nomi === "Olma" ? 12000 : null;
}

const a = narxi("Anor");
console.log(a === null ? "topilmadi" : a.toFixed(0));
console.log(narxi("Olma")?.toFixed(0));
console.log(narxi("Anor") ?? 0);
Terminal
tsx src/nul2.ts
Natija
topilmadi
12000
0
OperatorNomiNima qiladi
?.Ixtiyoriy zanjirnull/undefined bo'lsa, undefined qaytaradi
??Nullish birlashtirishnull/undefined bo'lsagina o'ngdagini oladi

?? ni || bilan aralashtirmang: 0 || 5 - 5, lekin 0 ?? 5 - 0.

Xulosa #

  • A | B - qiymat yo A, yo B; A & B - qiymat ikkalasi ham.
  • Union ustida faqat barcha a'zolarda bor xossa va metodlarni ishlatish mumkin.
  • Obyektlarda union maydonlarni kamaytiradi, intersection esa ko'paytiradi - nomlarga qarab teskari o'ylamang.
  • Literal union ("a" | "b") - ruxsat etilgan qiymatlar ro'yxati; u ish vaqtida hech qanday kod qoldirmaydi.
  • Ajratuvchi maydon (usul: "naqd") union a'zosini aniqlab beradi va qolgan maydonlarni ochadi.
  • default shoxidagi const qolgan: never = t; unionga yangi a'zo qo'shilganda unutilgan joylarni topib beradi.
  • string[] | number[] ga hech narsa qo'shib bo'lmaydi; kerakli yozuv odatda (string | number)[].
  • Ziddiyatli kesishmada maydon turi never bo'ladi, lekin tur e'loni xato bermaydi - muammo ishlatganda ko'rinadi.
  • never ga hech narsa berib bo'lmaydi, lekin uni istalgan turga berish mumkin.
  • ?. va ?? - null bilan union ustida ishlashning qisqa yo'llari.
Amaliy topshiriq
  1. string | number turidagi o'zgaruvchi yarating va unga boolean berib xato oling.
  2. Union ustida faqat bitta a'zoda bor metodni chaqirib, TS2339 xabarining ikkinchi qatorini o'qing.
  3. typeof bilan toraytirib, o'sha kodni ishlaydigan qiling.
  4. Uchta variantli literal union yarating va ro'yxatdan tashqari qiymat berib ko'ring.
  5. usul ajratuvchi maydonli ikkita to'lov turi yozing.
  6. Ularni if bilan ajratib, faqat bittasida bor maydonga murojaat qiling.
  7. Unionga uchinchi a'zo qo'shing va never tekshiruvi qaysi qatorni ko'rsatishini kuzating.
  8. string[] | number[] ga push qilib, never xatosini chaqiring, keyin (string | number)[] ga o'zgartiring.
  9. Ziddiyatli A & B yarating va maydon turi never ekanini isbotlang.
  10. number | null qaytaruvchi funksiya yozing va natijani ?., ?? hamda === null - uch xil usulda ishlating.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.