4 β Massivlar, tuple va enum¶
β¬ οΈ Oldingi: 03 β Asosiy tiplar va type inference Β· π README Β· Keyingi: 05 β Object tiplari va interface β‘οΈ
Bu bobda: bir turdagi qiymatlar ro'yxatini (massiv) va aniq tartibdagi qiymatlar to'plamini (tuple β uzunligi va har pozitsiya tipi qat'iy belgilangan ro'yxat) tiplashni o'rganamiz:
number[]vaArray<number>, aralash(string | number)[],readonly, ko'p o'lchovli massivlar, tuple'ning optional/rest/named elementlari, destructuring; so'ng nomli konstantalar uchun enum (numeric, string,const enum) va nega 2026-da ko'p hollarda enum o'rniga union literal afzal ekanini ko'rib chiqamiz.
Muammo¶
JavaScript'da massiv β eng ko'p ishlatadigan narsangiz. U yerda massivga istalgan narsani solishtiravering, hech kim to'xtatmaydi:
// oddiy JavaScript β hamma narsa joyida ko'rinadi
let baholar = [5, 4, 3];
baholar.push("a'lo"); // hech kim e'tiroz bildirmadi...
let ortacha = baholar.reduce((a, b) => a + b, 0) / baholar.length;
console.log(ortacha); // NaN β chunki ichida "a'lo" bor!
Bu xato ishga tushganda (runtime'da), ko'pincha foydalanuvchi ekranida NaN ko'rinib qolganda bilinadi. Massiv "ichida nima bor"ligini JavaScript eslab turmaydi.
Yana bir muammo β tartib. RGB rang uchta sondan iborat: [255, 128, 0]. Lekin oddiy massivda nima uchun aynan uchta? Nega sonlar? Kim adashib [255, 128] yoki ["255", 128, 0] yozsa, JavaScript baribir indamaydi:
function rangKodi([r, g, b]) {
return `rgb(${r}, ${g}, ${b})`;
}
rangKodi([255, 128]); // "rgb(255, 128, undefined)" β buzilgan, lekin xato yo'q
TypeScript ikkala muammoni ham yozish paytida hal qiladi: massiv tipi orqali "bu yerda faqat sonlar" deb belgilaysiz, tuple orqali esa "aniq 3 ta son, mana shu tartibda" deysiz. Keling, boshlaymiz.
JavaScript massivlari va metodlari (map, filter, reduce, destructuring) yodingizdan ko'tarilgan bo'lsa, JavaScript kitobiga qaytib o'ting β bu bobda ularning ustiga faqat tip qatlamini qo'shamiz.
Massiv tiplari: ikki yozuv, bitta ma'no¶
Bir turdagi qiymatlar ro'yxatini tiplashning ikki yo'li bor β ikkalasi bir xil narsani anglatadi:
let sonlar: number[] = [1, 2, 3]; // 1-uslub: qisqa
let ismlar: Array<string> = ["Aziz", "Malika"]; // 2-uslub: generic
number[] β "sonlar massivi", Array<string> β "stringlar massivi". number[] qisqaroq va keng tarqalgan, shuning uchun amalda ko'pincha o'shani yozasiz. Array<string> esa generic (umumlashgan tip β keyinroq 11-bobda chuqur ko'ramiz) yozuvi; ba'zan murakkab tiplarda qulayroq.
Endi push ham himoyalangan:
let sonlar: number[] = [1, 2, 3];
sonlar.push(4); // β
son β joyida
sonlar.push("salom"); // β Xato:
// Argument of type 'string' is not assignable to parameter of type 'number'.
π E'tibor bering: bu xato terminalga tsc ishlatganda yoki muharrirda qizil chiziq ko'rinishida chiqadi, dasturni ishga tushirishdan oldin. Muammodagi NaN endi paydo bo'lmaydi, chunki noto'g'ri qiymat massivga umuman kira olmaydi.
π‘ 3-bobdan eslang β type inference (tipni o'zi aniqlash) massivlarda ham ishlaydi. : number[] yozmasangiz ham TypeScript o'zi topadi:
let baholar = [5, 4, 3, 5]; // TypeScript buni number[] deb biladi
baholar.push(2); // β
baholar.push("a'lo"); // β Xato: string -> number emas
Shuning uchun ko'pincha tipni yozmasa ham bo'ladi β boshlang'ich qiymat tipni aytib turadi.
Aralash massiv β union bilan¶
Massivda ikki xil tipni saqlash kerak bo'lsa, union (bir nechta tipdan biri β 7-bobda batafsil) ishlatiladi. Lekin qavslarga e'tibor bering:
π Qavs muhim: (string | number)[] β "har elementi string yoki number bo'lgan massiv". Qavssiz string | number[] esa butunlay boshqa narsa: "yo bitta string, yo number massivi". Bittagina qavs ma'noni butunlay o'zgartiradi.
readonly massiv β o'zgarmas ro'yxat¶
Massivni "muzlatib", o'zgartirishni taqiqlamoqchi bo'lsangiz readonly qo'ying:
let ranglar: readonly string[] = ["qizil", "yashil"];
let koords: ReadonlyArray<number> = [10, 20]; // bir xil ma'no, generic yozuv
console.log(ranglar[0]); // β
o'qish β mumkin
ranglar.push("kok"); // β Xato:
// Property 'push' does not exist on type 'readonly string[]'.
ranglar[0] = "qora"; // β Xato:
// Index signature in type 'readonly string[]' only permits reading.
π‘ readonly massivda push, pop, splice kabi o'zgartiruvchi metodlar yo'qoladi β faqat o'qish qoladi. Bu konstantalar, sozlamalar yoki funksiyaga "men buni o'zgartirmayman" deb va'da bermoqchi bo'lganingizda juda foydali.
Ko'p o'lchovli massiv¶
number[][] β "sonlar massivi massivi", ya'ni jadval (matritsa):
[] har qancha qo'shsangiz, shuncha o'lcham: number[][][] β uch o'lchovli kub.
Massiv metodlari to'liq tiplangan¶
JavaScript metodlari (map, filter, reduce) TypeScript'da tiplarni avtomatik kuzatib boradi. Callback ichidagi parametr tipini yozmasangiz ham TypeScript biladi:
let narxlar = [100, 250, 75]; // number[]
let chegirma = narxlar.map((n) => n * 0.9); // n: number, natija: number[]
let qimmat = narxlar.filter((n) => n > 80); // number[]
let jami = narxlar.reduce((a, b) => a + b, 0); // number
let ismlar = ["aziz", "malika"];
let katta = ismlar.map((s) => s.toUpperCase()); // s: number emas β string!
π map natijasining tipi callback nima qaytarishiga qarab o'zgaradi: narxlar.map((n) => n > 80) natijasi number[] emas, boolean[] bo'ladi. Bularning hammasini TypeScript siz yozmasangiz ham o'zi hisoblaydi.
Tuple β uzunligi va tartibi qat'iy ro'yxat¶
Massiv "qancha bo'lsa shuncha bir xil element" deydi. Tuple (aniq uzunlik va har pozitsiyada aniq tip) esa boshqacha: "aynan shuncha element, har biri o'z tipida, mana shu tartibda".
let nuqta: [number, number] = [10, 20]; // x va y
let foydalanuvchi: [string, number] = ["Aziz", 30]; // ism, yosh
Tuple massivga o'xshab ko'rinadi (kvadrat qavs), lekin tip e'lonida elementlar sanab beriladi. Endi har pozitsiyaning tipi aniq:
let nuqta: [number, number] = [10, 20];
let x = nuqta[0]; // x: number
let y = nuqta[1]; // y: number
Massivda yo'q bo'lgan cheklovlar tuple'da bor β adashishlar darrov ushlanadi:
let nuqta: [number, number] = [10, 20];
let uch: [number, number] = [10, 20, 30]; // β Xato:
// Source has 3 element(s) but target allows only 2.
let bir: [number, number] = [10]; // β Xato:
// Source has 1 element(s) but target requires 2.
let teskari: [string, number] = [30, "Aziz"]; // β Xato:
// Type 'number' is not assignable to type 'string'.
π Tuple vs massiv β eng muhim farq. [number, number] va number[] bir xil emas. Funksiya tuple kutsa, oddiy massiv bermaysiz:
function masofa(a: [number, number], b: [number, number]): number {
return Math.hypot(b[0] - a[0], b[1] - a[1]);
}
let p: number[] = [1, 2];
masofa(p, [3, 4]); // β Xato:
// Argument of type 'number[]' is not assignable to parameter of type '[number, number]'.
// Target requires 2 element(s) but source may have fewer.
Mantiq: number[] ichida 0, 1 yoki 100 ta element bo'lishi mumkin β TypeScript "aynan 2 ta" deb kafolat bera olmaydi. Tuple esa kafolat beradi.
π Tuple chegarasidan tashqari indeks ham xato beradi (massivda bunday cheklov yo'q):
let nuqta: [number, number] = [10, 20];
console.log(nuqta[2]); // β Xato:
// Tuple type '[number, number]' of length '2' has no element at index '2'.
let massiv: number[] = [10, 20];
console.log(massiv[2]); // β
kompilyatsiya o'tadi (natija: undefined)
Tuple destructuring¶
JavaScript destructuring'i tuple bilan ayniqsa chiroyli ishlaydi β har o'zgaruvchi to'g'ri tipni oladi:
let nuqta: [number, number] = [10, 20];
let [enlik, kenglik] = nuqta; // enlik: number, kenglik: number
let foydalanuvchi: [string, number] = ["Aziz", 30];
let [ism, yosh] = foydalanuvchi;
console.log(ism.toUpperCase()); // β
ism β string, .toUpperCase() bor
console.log(yosh + 1); // β
yosh β number
π‘ React'dagi useState shuning uchun aynan tuple qaytaradi: const [son, setSon] = useState(0). Birinchi element β qiymat (number), ikkinchisi β uni o'zgartiruvchi funksiya. Tuple ularni bitta qaytaruv qiymatida, har biri o'z tipida saqlaydi. Buni o'zingiz ham yozishingiz mumkin:
function juftlik(): [number, () => void] {
let qiymat = 0;
return [qiymat, () => console.log("bosildi")];
}
let [son, funk] = juftlik(); // son: number, funk: () => void
funk(); // "bosildi"
Named, optional va rest tuple elementlari¶
Named tuple β pozitsiyalarga nom berib, kodni o'qiluvchanroq qiladi (faqat hujjat uchun, natijaga ta'sir qilmaydi):
let masofa: [boshi: number, oxiri: number] = [0, 100];
// muharrirda nuqtani ko'rsatganda "boshi" va "oxiri" deb ko'rsatadi
Optional element (?) β bo'lishi shart bo'lmagan oxirgi elementlar:
let sozlama: [string, number?] = ["dark"]; // β
ikkinchisi yo'q
let sozlama2: [string, number?] = ["light", 80]; // β
ikkinchisi bor
Rest element (...) β qolgan istalgancha bir xil tipli elementlar:
let yozuv: [string, ...number[]] = ["natijalar", 10, 20, 30]; // β
// birinchisi β sarlavha (string), qolgani β istalgancha son
readonly tuple β massivdagi kabi, muzlatish:
let muzlatilgan: readonly [number, number] = [3, 4];
muzlatilgan[0] = 5; // β Xato: faqat o'qish mumkin
Enum β nomli konstantalar to'plami¶
Ba'zan qiymat aniq ro'yxatdan biri bo'lishi kerak: yo'nalish faqat "yuqori/past/chap/ong", holat faqat "faol/tugagan/...". JavaScript'da buni odatda "sehrli string"lar yoki sonlar bilan qilardingiz:
let yonalish = "yuqori"; // adashib "yuqary" yozsangiz β hech kim aytmaydi
let holat = 1; // 1 nimani anglatadi? kim biladi...
enum (sanab o'tiluvchi tip β nomli konstantalar to'plami) shu muammoni hal qiladi. Eng oddiy turi β numeric enum:
enum Yonalish {
Yuqori, // 0
Past, // 1
Chap, // 2
Ong, // 3
}
let q: Yonalish = Yonalish.Yuqori;
console.log(q); // 0
console.log(Yonalish.Ong); // 3
TypeScript a'zolarga 0 dan boshlab avtomatik son beradi. Endi Yonalish.Yuqori deb yozasiz β adashib bo'lmaydi, muharrir ham to'rttala variantni taklif qiladi.
π Numeric enum ikki tomonlama ishlaydi (reverse mapping): nomdan songa ham, sondan nomga ham:
String enum β o'qiladigan qiymatlar¶
Numeric enum'dagi 0, 1 qiymatlari log'da yoki ma'lumotlar bazasida tushunarsiz ko'rinadi. String enum har a'zoga aniq matn beradi:
enum Holat {
Faol = "FAOL",
Tugagan = "TUGAGAN",
Kutilmoqda = "KUTILMOQDA",
}
let h: Holat = Holat.Faol;
console.log(h); // "FAOL" β log'da ham tushunarli
π‘ String enum'da reverse mapping yo'q (Holat["FAOL"] ishlamaydi), lekin amalda string enum ko'pincha afzal: qiymatlar API javobida, log'da, bazada o'qiladigan ko'rinishda saqlanadi.
enum kompilyatsiyadan keyin nimaga aylanadi?¶
TypeScript tiplari odatda kompilyatsiyada o'chib ketadi β JavaScript'ga aylanganda iz qolmaydi. Lekin enum istisno: u haqiqiy JavaScript obyektiga aylanadi. Shuning uchun enum nafaqat tip, balki kodda yashaydigan qiymat hamdir.
// Kompilyatsiyadan keyin (taxminan):
var Yonalish;
(function (Yonalish) {
Yonalish[Yonalish["Yuqori"] = 0] = "Yuqori";
Yonalish[Yonalish["Past"] = 1] = "Past";
})(Yonalish || (Yonalish = {}));
// natijada: { 0: "Yuqori", 1: "Past", Yuqori: 0, Past: 1 }
const enum β kompilyatsiyada butunlay o'chadi¶
Agar enum'ni faqat qiymatlarni nomlash uchun ishlatsangiz va yuqoridagi qo'shimcha obyekt kerak bo'lmasa, const enum ishlating. U JavaScript'ga aylanganda butunlay yo'qoladi β har bir ishlatilgan joyiga to'g'ridan-to'g'ri qiymat qo'yiladi:
π const enum kichikroq va tezroq JavaScript beradi, lekin ba'zi build sozlamalari (masalan isolatedModules) bilan muammo chiqarishi mumkin. Shubha bo'lsa β oddiy enum yoki keyingi bo'limdagi union literal'ni tanlang.
enum vs union literal β 2026-da qaysi biri?¶
Mana eng muhim tavsiya. Ko'p hollarda enum'ga umuman ehtiyoj yo'q β uning o'rniga union literal (aniq qiymatlar to'plamidan iborat tip) ishlatish zamonaviyroq va yengilroq:
// enum o'rniga:
type Yonalish = "yuqori" | "past" | "chap" | "ong";
let yu: Yonalish = "chap"; // β
let xato: Yonalish = "tepa"; // β Xato:
// Type '"tepa"' is not assignable to type 'Yonalish'.
Yonalish endi shunchaki bir tip β to'rtta matndan biri. Funksiyaga ham to'g'ridan-to'g'ri beraverasiz:
function harakat(yon: Yonalish): void {
console.log("Harakat:", yon);
}
harakat("ong"); // β
harakat("tepa"); // β Xato: ruxsat etilgan qiymat emas
Nega union literal ko'pincha afzal:
| Jihati | enum |
union literal ("a" \| "b") |
|---|---|---|
| Kompilyatsiyada JS kod | qoldiradi (qo'shimcha obyekt) | iz qolmaydi (faqat tip) |
| Qiymatlar | Holat.Faol deb yozasiz |
to'g'ridan-to'g'ri "faol" |
| Import qilish | enum'ni import qilish kerak | hech narsa kerak emas |
| API/JSON bilan | qiymatni moslashtirish kerak | matn aynan mos keladi |
| Soddalik | ko'proq sintaksis | minimal |
π‘ Union literal bilan ham to'liqlik tekshiruvi (exhaustiveness check) qilish mumkin. never tipidan (hech qachon bo'lmaydigan qiymat β 9-bobda batafsil) foydalanib, switch'da biror variantni unutib qoldirsangiz, TypeScript ogohlantiradi:
type Yonalish = "yuqori" | "past" | "chap" | "ong";
function burchak(y: Yonalish): number {
switch (y) {
case "yuqori": return 0;
case "past": return 180;
case "chap": return 270;
case "ong": return 90;
default:
const tekshir: never = y; // bu yerga hech qachon yetib kelmaydi
return tekshir;
}
}
Endi Yonalishga yangi qiymat (masalan "ortada") qo'shsangiz, lekin switchni yangilashni unutsangiz:
type Yonalish = "yuqori" | "past" | "chap" | "ong" | "ortada"; // yangi qiymat
// ... switch o'sha-o'sha ...
default:
const tekshir: never = y; // β Xato:
// Type '"ortada"' is not assignable to type 'never'.
Bu β bepul "esdan chiqarmaslik" mexanizmi: yangi holatni qayerda qo'shish kerakligini TypeScript o'zi ko'rsatib beradi.
π Qachon enum hali ham mantiqiy? Numeric qiymatlar muhim bo'lganda (masalan bit bayroqlari), yoki katta jamoa enum'larga o'rganib qolgan eski kodda. Yangi kod yozayotganda esa β avval union literal'ni o'ylab ko'ring.
π‘ Union literal'ni as const bilan birga ishlatish ham keng tarqalgan. Massivni as const qilsangiz, u o'zgarmas tuple'ga aylanadi va qiymatlar aniq literal bo'lib qoladi:
const olchamlar = ["S", "M", "L"] as const;
// tip: readonly ["S", "M", "L"]
type Olcham = (typeof olchamlar)[number]; // "S" | "M" | "L"
Bu β "yagona haqiqat manbai": ro'yxatni bir joyda yozasiz, tip esa undan avtomatik kelib chiqadi. (typeof va keyof kabi imkoniyatlarni 12-bobda chuqur ko'ramiz.)
Xulosa¶
- Massiv:
number[]yokiArray<number>β bir turdagi istalgancha element. Aralash uchun(string | number)[], muzlatish uchunreadonly number[]. - Tuple:
[string, number]β aniq uzunlik, har pozitsiyada aniq tip. Optional (?), rest (...), named vareadonlyvariantlari bor. Destructuring bilan ayniqsa qulay. - Enum: nomli konstantalar. Numeric (0, 1, ...), string (
"FAOL"),const enum(kompilyatsiyada o'chadi). Enum tip emas β kompilyatsiyada JS obyekti qoldiradi. - 2026 tavsiyasi: ko'p hollarda enum o'rniga union literal (
"a" | "b") ishlating β yengilroq, JS izi qolmaydi,neverbilan to'liqlik tekshiruvi mumkin.
Keyingi bobda obyektlarni tiplashga β interfacega o'tamiz.
4-bob mashqlari¶
Yechimlarni yozmadim β har birini o'zingiz
tsc --noEmit --strictbilan tekshiring. Ataylab xatoli deb belgilangan joylarda haqiqatan xato chiqishini ko'ring.
number[]tipidabahollarmassivini e'lon qiling va 5, 4, 3 qiymat bering. Ungapushbilan yana bitta son qo'shing.- Bir xil massivni
Array<string>yozuvi bilan e'lon qiling (tillarβ dasturlash tillari ro'yxati). Ikkala yozuv bir xil natija berishiga ishonch hosil qiling. - Type inference'ga tayanib (tipni o'zingiz yozmasdan)
narxlar = [100, 250, 75]deb e'lon qiling, so'ng ungastringqo'shib ko'ring β qanday xato chiqadi? (string | number)[]tipida aralash massiv yarating. So'ng qavsni olib tashlabstring | number[]qilib ko'ring va ma'no qanday o'zgarishini kuzating.readonly string[]tipidahaftaKunlarimassivini yarating va ungapushqilishga uringa β chiqqan xato matnini o'qing.number[][]tipida 3x3 matritsa yarating va uning markaziy katagini ([1][1]) o'qing.narxlarmassivigamapqo'llab har bir narxni 20% kamaytiring, natija tipi nima bo'lishini tekshiring (muharrirda kursorni qo'yib ko'ring).- Xuddi shu massivga
filterqo'llab faqat 100 dan katta narxlarni qoldiring, so'ngreducebilan ularning yig'indisini hisoblang. [number, number]tuple tipidakoordinatae'lon qiling (x, y). Unga uchta element berib ko'ring β xato matnini o'qing.[number, number, number]tuple tipida RGB rang e'lon qiling. So'ng uni[r, g, b]destructuring bilan uchta o'zgaruvchiga ajrating.[string, number]tuple tipidafoydalanuvchi(ism, yosh) e'lon qiling. Qiymatlarni teskari ([30, "Aziz"]) berib ko'ring va xatoni ko'ring.[boshi: number, oxiri: number]named tuple e'lon qiling. Muharrirda[0]indeksiga kursor qo'yib, nom ko'rinishini tekshiring.[string, number?]optional tuple yarating. Avval ikkinchi elementsiz, so'ng u bilan qiymat bering.[string, ...number[]]rest tuple yarating: birinchisi β sarlavha, qolgani β istalgancha son. Kamida 4 element bering.readonly [number, number]tuple yarating va birinchi elementini o'zgartirishga uringa β qanday xato chiqadi?function masofa(a: [number, number], b: [number, number]): numberyozing (Math.hypot bilan). Unganumber[]tipidagi o'zgaruvchi berib ko'ring β nega xato chiqadi?numeric enumKunyarating (Dushanba, Seshanba, ...).Kun.Seshanbaqiymatini vaKun[1](reverse mapping) ni log qiling.string enumHolatyarating (Faol = "FAOL",Tugagan = "TUGAGAN").Holat.Faolni log qilib, qiymat aynan"FAOL"ekanini ko'ring.const enumOlchamyarating. Uni qiymatga bering. (Imkoni bo'lsa)tscbilan JS'ga kompilyatsiya qilib, enum kodning chiqishda yo'qolganini ko'ring.- 17-mashqdagi
Kunenum'ini union literal ("dushanba" | "seshanba" | ...) bilan almashtiring. So'ngneverishlatib, switch ichida bitta kunni unutib qoldiring va to'liqlik tekshiruvi xatosini ko'ring.