IlmHamroh
JavaScript Full-stack/12-qism. JavaScript: ilg'or mavzular va kod sifati39/44-dars24 daqiqa
Mundarija (33)

JSDoc va // @ts-check: oddiy JavaScript'da turlarni tekshirish

Qisqacha: JSDoc — funksiya ustidagi /** … */ izoh: unda parametrlar va natijaning turi yoziladi (@param {number} price). Fayl boshiga // @ts-check qo'ysangiz, VS Code bu izohlarni o'qib, noto'g'ri turdagi qiymatni kod ishga tushmasdan qizil chiziq bilan ko'rsatadi. Terminalda xuddi shu tekshiruvni TypeScript kompilyatori — tsc qiladi. Kod o'zgarmaydi: u oddiy JavaScript bo'lib qoladi.

Bu darsda

  • JSDoc bilan funksiya parametrlari va natijasining turini yozasiz: @param, @returns, @type, @typedef.
  • // @ts-check va jsconfig.json bilan tur tekshiruvini yoqasiz, tsc xabarlarini o'qiysiz.
  • "possibly 'undefined'", "implicitly has an 'any' type" kabi xatolarni tuzatasiz va turni toraytirish (narrowing) nima ekanini tushuntira olasiz.
  • JSDoc va TypeScript farqini va nega bu dars TypeScript'ga eshik ekanini bilasiz.

Oldin bilishingiz kerak: ESLint va Prettier, Toza kod: funksiyalar, izohlar va tuzilma, typeof va turni to'g'ri aniqlash.

1. Nega bu kerak?

Oldingi darsda ESLint jaml kabi e'lon qilinmagan nomni ishga tushirmasdan topdi. Lekin uning ham ko'r joyi bor. Mana Sardorning yangi funksiyasi:

js
function totalPrice(price, quantity) {
  return price * quantity;
}

console.log(totalPrice(35000, 2)); // 70000
console.log(totalPrice("35 000", 2)); // NaN

Ikkinchi chaqiruvda price forma maydonidan satr bo'lib keldi va ichida bo'sh joy bor. Natija — NaN (son emas). Hech qanday xato yo'q, dastur jim davom etadi va chekda "NaN so'm" chiqadi. ESLint bu yerda hech narsa demaydi: kod sintaktik jihatdan to'g'ri, hamma nom e'lon qilingan. U funksiyaga qaysi turdagi qiymat kelishini bilmaydi.

Muammoning ildizi — funksiyaning "shartnomasi" hech qayerda yozilmagan. totalPrice son kutadi, lekin buni faqat muallif biladi. Uch oydan keyin muallifning o'zi ham unutadi.

Bu darsda shartnomani izohga yozamiz va muharrirga uni tekshirishni o'rgatamiz. Kod o'sha-o'sha oddiy JavaScript bo'lib qoladi — hech qanday yangi til, yangi fayl kengaytmasi yo'q.

2. JSDoc

2.1 Birinchi JSDoc izohi

Toza kod: funksiyalar, izohlar va tuzilma darsida hujjat izohi haqida bir gap aytgan edik: /** … */ ichidagi maxsus izoh. Uning nomi — JSDoc. 08-qismda "kursda ko'rasiz" degan va'da ham shu edi (Sintaksis asoslari).

js
/**
 * Buyurtma narxini hisoblaydi.
 * @param {number} price bitta porsiya narxi, so'mda
 * @param {number} quantity nechta porsiya
 * @returns {number} jami narx
 */
function totalPrice(price, quantity) {
  return price * quantity;
}

console.log(totalPrice(35000, 2)); // 70000

Qatorma-qator:

  • /** — ikkita yulduzcha. Bitta yulduzchali /* oddiy izoh, uni hech kim o'qimaydi.
  • Birinchi qator — funksiya nima qilishi, oddiy gap bilan.
  • @param {number} price bitta porsiya narxi, so'mda — teg (@param; bu JSDoc tegi — @ bilan boshlanadigan belgi, HTML tegi emas), jingalak qavsda tur ({number}), parametr nomi (price) va tavsif. Nomlar — Toza kod: nomlash darsidagi qoida bo'yicha inglizcha, tavsif — o'zbekcha.
  • @returns {number} jami narx — funksiya nima qaytaradi.

Tur (type) — qiymat qaysi xilda ekani: son, satr, mantiqiy qiymat, massiv, obyekt. Siz turlarni typeof darsidan bilasiz. Farqi: typeof turni ishlash paytida so'raydi, JSDoc esa uni oldindan e'lon qiladi.

JSDoc kodning ishlashiga hech qanday ta'sir qilmaydi — bu baribir izoh. Lekin VS Code uni o'qiydi: totalPrice( deb yozishingiz bilan kichik oynada parametrlar, turlari va tavsifi chiqadi.

2.2 Tur yozuvlari

JSDoc ichidagi tur yozuvi TypeScript tilidan olingan. Ikki jadvalni yodlash shart emas — kerak bo'lganda shu yerga qaytasiz. Birinchi jadval — kundalik turlar:

Yozuv Ma'nosi Misol qiymat
{number}, {string}, {boolean} son, satr, mantiqiy 35000, "Osh", true
{string[]} satrlar massivi ["osh", "manti"]
{number | null} son yoki null 4, null
{{ name: string, price: number }} shu shakldagi obyekt { name: "Osh", price: 35000 }

Ikkinchi jadval — kamroq uchraydiganlari. Oxirgi ikkitasini «Kengroq imkoniyatlar» bo'limida misol bilan ko'ramiz:

Yozuv Ma'nosi Misol qiymat
{(d: Dish) => boolean} funksiya: Dish oladi, mantiqiy qaytaradi (d) => d.price < 30000
{Set<number>}, {Map<string, number>} to'plam, xarita new Set([1, 2])
{unknown} "hali noma'lum — avval tekshir" JSON.parse(...) natijasi
{any} "istalgan narsa — tekshirma" —

Uchta yangi belgi:

  • | — "yoki". Bu tur birlashma (union) deyiladi: number | null — son ham, null ham bo'lishi mumkin.
  • <number> — burchak qavsdagi tur "ichida nima bor" degani: Set<number> — sonlar to'plami.
  • (d: Dish) => boolean — strelkali funksiyaning "sxemasi": chapda parametr va uning turi, => dan keyin natija turi. Dish — keyingi bo'limda o'zimiz yaratadigan tur.

Ixtiyoriy parametr kvadrat qavsda yoziladi: @param {boolean} [bajarildi]. Standart qiymati bo'lsa ham shunday.

2.3 O'z turingiz: @typedef

Bir xil obyekt shakli ko'p joyda uchrasa, unga nom beriladi:

js
/**
 * Menyudagi bitta taom.
 * @typedef {object} Dish
 * @property {string} name
 * @property {number} price so'mda
 * @property {boolean} [spicy] ixtiyoriy belgi
 */

/** @type {Dish[]} */
const menu = [
  { name: "Osh", price: 35000 },
  { name: "Lag'mon", price: 28000, spicy: true },
];

console.log(menu.length); // 2
  • @typedef {object} Dish — "Dish (taom) degan yangi tur — obyekt".
  • @property — uning xususiyatlari. [spicy] (achchiq) — ixtiyoriy: osh obyektida u yo'q, bu xato emas.
  • /** @type {Dish[]} */ — o'zgaruvchining turi: Dish lar massivi.

Endi istalgan funksiyada @param {Dish} dish deb yozasiz va muharrir dish. dan keyin name, price, spicy ni taklif qiladi.

Boshqa fayldagi turni olish uchun — @import:

js
/** @import { Dish } from "./menu.js" */

Bu import emas, faqat izoh: ishlash paytida hech narsa yuklanmaydi.

Tekshirib ko'ring: /* @param {number} price */ (bitta yulduzcha) yozilgan funksiyaga muharrir maslahat ko'rsatadimi?

Javob

Yo'q. JSDoc faqat /** (ikki yulduzcha) bilan boshlanadigan izohda o'qiladi. Bitta yulduzchali izoh — oddiy izoh, muharrir uni e'tiborsiz qoldiradi.

3. // @ts-check: tekshiruvni yoqish

3.1 Bitta qator

JSDoc o'zi faqat maslahat beradi. Uni tekshiruvga aylantirish uchun fayl boshiga bitta izoh qo'shiladi:

js
// @ts-check

VS Code ichida TypeScript'ning tekshiruvchisi bor — u JavaScript fayllari uchun ham ishlaydi, hech narsa o'rnatish shart emas. Fayl boshida // @ts-check bo'lsa, u JSDoc turlarini solishtiradi va mos kelmagan joyni qizil to'lqinli chiziq bilan belgilaydi.

3.2 Terminalda: tsc

Muharrir — bitta odamning kompyuterida. Butun loyihani terminalda (va keyin CI'da) tekshirish uchun TypeScript kompilyatori — tsc kerak. U typescript paketida:

bash
npm install --save-dev --save-exact typescript@7.0.2

TypeScript 7 — kompilyatori Go tilida qayta yozilgan yangi versiya. TypeScript — JavaScript'ga turlar qo'shilgan alohida til, uni 15-qismda o'rganamiz, hozir bilish shart emas. Bugun undan faqat bitta narsa olamiz — tekshiruvchi.

price.js (1-qatori // @ts-check, keyin yuqoridagi JSDoc'li totalPrice va ikki chaqiruv) uchun:

bash
npx tsc --noEmit --allowJs --checkJs price.js
  • --noEmit — "hech qanday fayl yaratma, faqat tekshir". (tsc aslida TypeScript'ni JavaScript'ga o'giradi, bizga bu kerak emas.)
  • --allowJs --checkJs — ".js fayllarni ham o'qi va tekshir".

Haqiqiy chiqish:

text
price.js(14,24): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

O'qilishi: price.js faylining 14-qatori, 24-ustuni; xato kodi TS2345. Tarjimasi: "string turidagi argumentni number turidagi parametrga berib bo'lmaydi". Aynan "35 000". Chiqish kodi — 1, ya'ni "xato bor". ESLint'dagi kabi, CI shu raqamga qarab tekshiruvni qizil qiladi.

Node'da shu fayl hech qanday xatosiz 70000 va NaN chiqaradi. tsc esa kodni ishga tushirmasdan, faqat izohlarga qarab topdi.

3.3 Uch tipik xabar

Endi @typedef dagi menu ga funksiya yozamiz:

js
/**
 * @param {string} name
 * @returns {number}
 */
function findPrice(name) {
  const dish = menu.find((t) => t.name === name);
  return dish.prise;
}

Node'da findPrice("Osh") — undefined (xatosiz!). tsc:

text
menu.js(23,10): error TS18048: 'dish' is possibly 'undefined'.
menu.js(23,15): error TS2551: Property 'prise' does not exist on type 'Dish'. Did you mean 'price'?
  1. 'dish' is possibly 'undefined' — "dish undefined bo'lishi mumkin". find hech narsa topmasa, undefined qaytaradi (Massivda qidirish va tekshirish). tsc buni biladi: find ning natija turi — Dish | undefined. Siz esa undefined ning xususiyatini o'qimoqchisiz — menyuda yo'q taomda bu TypeError beradi.
  2. Property 'prise' does not exist on type 'Dish'. Did you mean 'price'? — "Dish turida prise xususiyati yo'q. price ni nazarda tutdingizmi?". Imlo xatosi — @typedef tufayli topildi.

Tuzatilgan versiya:

js
// @ts-check

/**
 * @typedef {object} Dish
 * @property {string} name
 * @property {number} price so'mda
 */

/** @type {Dish[]} */
const menu = [{ name: "Osh", price: 35000 }];

/**
 * @param {string} name
 * @returns {number}
 */
function findPrice(name) {
  const dish = menu.find((t) => t.name === name);
  if (dish === undefined) {
    throw new TypeError(`Menyuda yo'q: ${name}`);
  }
  return dish.price;
}

console.log(findPrice("Osh")); // 35000

if (dish === undefined) dan keyin tsc biladi: pastda dish — aniq Dish. Bu turni toraytirish (narrowing) deyiladi: shart tekshirilgach, tur kichrayadi. typeof x === "number", x !== null, Array.isArray(x) ham toraytiradi.

Uchinchi tipik xabar — tur umuman yozilmagan parametr:

text
any.js(2,17): error TS7006: Parameter 'n' implicitly has an 'any' type.

Tarjimasi: "n parametri yashirincha any turini oldi". any — "istalgan narsa, tekshirma". Tur yozilmagan parametr shunday bo'ladi va tsc uni ham xato deydi. Tuzatish — @param {number} n.

Tekshirib ko'ring: Nega Node'da findPrice("Osh") xato bermay undefined qaytardi, lekin findPrice("Somsa") xato beradi?

Javob

"Osh" bor: dish — obyekt, uning prise xususiyati yo'q, JavaScript esa yo'q xususiyat uchun undefined qaytaradi. "Somsa" yo'q: dish ning o'zi undefined, undefined.prise esa TypeError: Cannot read properties of undefined. tsc ikkala xatoni ham kod ishga tushmasdan ko'rsatdi.

4. jsconfig.json: butun loyiha uchun

4.1 Sozlama fayli

Har safar uzun buyruq yozmaslik uchun sozlama loyiha ildizidagi jsconfig.json ga yoziladi (JSON fayl):

json
{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2024",
    "lib": ["esnext", "dom"],
    "module": "esnext",
    "moduleResolution": "bundler"
  },
  "include": ["assets/js/vazifa.js", "assets/js/royxat.js"]
}
  • allowJs, checkJs, noEmit — yuqoridagi bayroqlar, endi faylda.
  • strict — qat'iy rejim: yashirin any ga yo'l qo'yilmaydi, null/undefined doim hisobga olinadi. TypeScript 7 da u standart holda yoqilgan (yozmasangiz ham), lekin faylda aniq yozib qo'yish o'quvchiga tushunarli.
  • target va lib — qaysi JavaScript imkoniyatlari bor deb hisoblansin. esnext — eng yangilari (Object.groupBy, toSorted), dom — brauzer API'lari (document, fetch).
  • module, moduleResolution — import qanday o'qiladi. "bundler" so'zma-so'z "yig'uvchi vosita usulida" degani: import yo'llari zamonaviy brauzer va vositalar kabi o'qiladi. Bundler'ning o'zini 16-qismda o'rganamiz, hozir bilish shart emas — shu qiymatni ko'chirib qo'yish yetarli.
  • include — qaysi fayllar tekshiriladi. Hamma fayl emas, faqat ro'yxatdagilar — tekshiruvni asta-sekin kengaytirish uchun qulay.

checkJs: true bo'lsa, include dagi hamma fayl tekshiriladi. Unda // @ts-check qatori shart emas, lekin uni qoldirish foydali: VS Code bu faylni jsconfig.json siz ham tekshiradi va o'quvchi fayl tekshirilishini birinchi qatordan ko'radi.

Ishga tushirish:

bash
npx tsc --noEmit -p jsconfig.json

-p — "shu sozlama faylini ishlat". package.json ga skript qilib qo'yiladi.

4.2 strict va 73 xato

Mavjud loyihaga strict: true bilan tekshiruv qo'shsangiz, birinchi natija qo'rqitishi mumkin. vazifalar ning to'rt modulida, hali birorta JSDoc yo'q paytda, tsc 73 ta xato berdi. Lekin turlariga qarang:

tsc: 73 xato turlari bo'yicha (JSDoc'siz, strict)
  • TS7006parametr turi yozilmagan63 xato
  • TS7031destrukturlangan parametr turi yo'q4 xato
  • TS7008klass maydoni any[]2 xato
  • TS7053obyektga yangi kalit2 xato
  • TS2339xususiyat yo'q1 xato
  • TS2739majburiy xususiyatlar yetishmaydi1 xato

Manba: O'lchandi: tsc 7.0.2 --noEmit -p jsconfig.json (strict: true), vazifalar #38 holati + // @ts-check, JSDoc'siz; Node 24.21, 2026-10-05

73 tadan 69 tasi — "tur yozilmagan" (TS70xx): kod buzuq emas, faqat tsc ga shartnoma aytilmagan. Haqiqiy muammolar — oxirgi ustunlarda. strict: false bilan tekshirib ko'rsangiz, faqat bitta xato qoladi. Shuning uchun 73 ni ko'rib qo'rqmang: avval JSDoc yozasiz, keyin haqiqiy topilmalar ko'rinadi.

Maslahat: Tekshiruvni birdan hamma faylga yoqmang. Avval DOM'ga bog'lanmagan, "sof" modullarni oling (ular kamroq tur talab qiladi), include ga qo'shing va tozalang. Qolganlarini TEXNIK-QARZ.md ga yozing. Bu oldingi darslardagi "qism-qism" qoidasi.

Tekshirib ko'ring: tsc 73 ta xato berdi. Bu kodda 73 ta bug bor degani-mi?

Javob

Yo'q. 69 tasi — "tur yozilmagan" xabarlari (TS70xx): kod ishlaydi, faqat tsc ga shartnoma aytilmagan. Ular JSDoc yozilgach yo'qoladi. Haqiqiy muammolar — qolgan bir nechtasi, ularni keyin birma-bir ko'rib chiqasiz.

5. Kengroq imkoniyatlar

5.1 unknown va tekshiruv

JSON.parse natijasi — server yoki foydalanuvchidan kelgan, ichida nima borligini bilmaysiz. Uni unknown deb belgilash halol:

js
/** @type {unknown} */
const raw = JSON.parse(text);
return raw.guests;
text
guests.js(6,10): error TS18046: 'raw' is of type 'unknown'.

Tarjimasi: "raw — unknown turida". unknown qiymatning xususiyatini o'qib bo'lmaydi — avval tekshirish kerak. Bu kuchli himoya: paketniOqi dagi kabi tekshiruvni unutsangiz, tsc eslatadi.

5.2 Tur predikati

Tekshiruvni alohida funksiyaga olsangiz, tsc ga u nimani isbotlashini aytish kerak:

js
/**
 * @param {unknown} qiymat
 * @returns {qiymat is Record<string, unknown>}
 */
function oddiyObyektmi(qiymat) {
  return (
    typeof qiymat === "object" &&
    qiymat !== null &&
    !Array.isArray(qiymat)
  );
}

@returns {qiymat is Record<string, unknown>} — tur predikati (type predicate): "true qaytarsam, qiymat — kalitlari satr bo'lgan obyekt". Record<string, unknown> — "kalitlari satr, qiymatlari hali noma'lum obyekt" degani. if (oddiyObyektmi(x)) ichida tsc x ni shunday deb biladi. Bu vazifalar ning paket.js idan. Funksiya nomi "-mi" bilan tugashi (Toza kod: nomlash) ham predikat ekanini aytib turibdi.

5.3 asserts va @throws: "qaytdimmi — demak, to'g'ri"

Predikat true/false qaytaradi va siz uni if ichida ishlatasiz. Ba'zi tekshiruvchi funksiyalar esa hech narsa qaytarmaydi: qiymat noto'g'ri bo'lsa, xato tashlaydi. Ularga assertion ("tasdiqlash") turi yoziladi:

js
// @ts-check

/**
 * Qiymat satr bo'lmasa, xato tashlaydi.
 * @param {unknown} value
 * @returns {asserts value is string}
 * @throws {TypeError} satr bo'lmasa
 */
function assertString(value) {
  if (typeof value !== "string") {
    throw new TypeError("Satr kutilgan edi");
  }
}

/** @type {unknown} */
const input = JSON.parse('"Osh"');
assertString(input);
console.log(input.toUpperCase()); // OSH
  • @returns {asserts value is string} — "funksiya xatosiz qaytsa, value — satr". Shu chaqiruvdan pastda tsc input ni satr deb biladi. assertString(input); qatorini o'chirsangiz, tsc oxirgi qatorda 'input' is of type 'unknown' (TS18046) deydi.
  • @throws {TypeError} — "bu funksiya TypeError tashlashi mumkin". tsc buni tekshirmaydi, bu o'quvchi uchun hujjat: funksiyani chaqirgan odam try...catch kerakmi-yo'qmi biladi.

vazifalar dagi malumotlarniTekshir — aynan shunday assertion funksiya (Vazifalar qadamida ko'rasiz).

5.4 Tur o'zgartirish (cast) — qavs bilan

Ba'zan siz tsc dan ko'proq bilasiz. Masalan, fetch faqat Error tashlashini bilasiz, lekin catch dagi qiymat unknown. Unda tur "aytib qo'yiladi":

js
const { name } = /** @type {Error} */ (error);

Qavs majburiy. Qavssiz yozilsa, tsc izohni e'tiborsiz qoldiradi:

text
cast.js(5,34): error TS18046: 'error' is of type 'unknown'.

Cast — "menga ishon" degani. Uni kam ishlating va yoniga nega ishonish mumkinligini izoh qilib yozing.

Tekshirib ko'ring: JSON.parse natijasini {any} emas, {unknown} deb belgilash nega yaxshiroq?

Javob

any — "tekshirma": raw.guests ni xatosiz o'qishga ruxsat beradi, guests yo'q bo'lsa, xato faqat ishlash paytida chiqadi. unknown — "avval tekshir": typeof, in yoki predikat bilan shaklini isbotlamaguningizcha tsc xususiyatni o'qitmaydi. Ya'ni tekshiruvni unutish imkoni qolmaydi.

6. TypeScript'ga ko'prik

Yuqoridagi totalPrice TypeScript tilida shunday yoziladi (.ts fayl):

ts
function totalPrice(price: number, quantity: number): number {
  return price * quantity;
}

Turlar izohda emas, kodning o'zida: price: number. G'oya bir xil — o'sha tekshiruvchi, o'sha xabarlar (TS2345). Farqi:

JSDoc + @ts-check TypeScript (.ts)
Fayl oddiy .js, brauzer to'g'ridan-to'g'ri ishlatadi .ts, avval JavaScript'ga o'giriladi
Yozuv izohda, uzunroq kodda, qisqa
Boshlash bitta qator qo'shiladi loyiha sozlanadi
Imkoniyatlar ko'pi bor to'liq

Ba'zi jamoalar ataylab JSDoc'da qoladi — masalan, Svelte freymvorki 2023-yilda o'z kodini TypeScript fayllaridan JSDoc'li JavaScript'ga o'tkazgan: o'girish bosqichisiz ishlash qulayroq bo'lgani uchun. Ko'pchilik loyihalar esa TypeScript'da. Bu darsda o'rgangan hamma narsa — tur yozuvlari, unknown, toraytirish, predikat — 15-qismda to'g'ridan-to'g'ri kerak bo'ladi.

flowchart LR
  A["JSDoc izohlari<br/>@param, @typedef"] --> B["TypeScript<br/>tekshiruvchisi"]
  B --> C["VS Code:<br/>qizil chiziq"]
  B --> D["tsc --noEmit:<br/>terminal va CI"]
  A -.-> E["Node va brauzer:<br/>izohni o'qimaydi"]

Diagrammaga qarang: izoh ikki yo'ldan boradi. Tekshiruvchi uni o'qiydi va xatolarni ko'rsatadi. Kodni ishga tushiradigan Node va brauzer esa uni oddiy izoh deb tashlab yuboradi — tur xatosi bo'lsa ham kod ishlayveradi. Tekshiruv faqat siz uni ishga tushirganingizda ishlaydi.

7. Ko'p uchraydigan xatolar

7.1 // @ts-check kod ostida

js
const a = 1;
// @ts-check

Tekshiruv ishlamaydi — tsc hech narsa demaydi. Tuzatish: // @ts-check faylning eng boshida, birinchi koddan oldin bo'lsin.

7.2 @param nomi parametrga mos emas

text
name.js(2,21): error TS8024: JSDoc '@param' tag has name 'pric', but there is no parameter with that name.

Tarjimasi: "JSDoc'dagi @param tegida pric nomi bor, lekin bunday parametr yo'q". Parametrni qayta nomlaganda izohni unutish — tez-tez uchraydi. Tuzatish: izohdagi nomni ham o'zgartiring. VS Code'dagi "Rename Symbol" (F2) ikkalasini birga o'zgartiradi.

7.3 Xatoni @ts-expect-error bilan "yopish"

// @ts-expect-error — "keyingi qatorda xato kutilyapti, ko'rsatma". Keyingi qatorda xato bo'lmay qolsa, tsc buni ham aytadi:

text
kut.js(8,1): error TS2578: Unused '@ts-expect-error' directive.

Tarjimasi: "Ishlatilmagan @ts-expect-error direktivasi". Bu ESLint'dagi eslint-disable-next-line ning tur tekshiruvidagi o'xshashi. Qoida: faqat haqiqatan zarur joyda, sababi bilan. Xatoni "yopish" emas, tuzatish kerak.

7.4 Number.isInteger tur toraytiradi deb o'ylash

id — unknown bo'lsa, !Number.isInteger(id) || id < 1 da tsc id < 1 ni qabul qilmaydi (TS18046). Number.isInteger true qaytarsa ham, tsc id son ekanini bilmaydi. Tuzatish: oldiga typeof id !== "number" || qo'shing. Ishlash paytidagi natija bir xil, tsc esa endi ishonadi.

7.5 JSDoc'ni bir marta yozib, tekshirmaslik

// @ts-check va tsc yo'q bo'lsa, JSDoc oddiy izoh: kod o'zgaradi, izoh esa eskicha qoladi va yolg'on gapira boshlaydi. Tuzatish: JSDoc yozilgan joyda tekshiruv ham bo'lsin (npm run tip yoki CI).

8. Mashqlar

1-mashq (oson): Birinchi JSDoc

Funksiyaga JSDoc yozing: name — satr, guests — son, time — ixtiyoriy satr; funksiya satr qaytaradi.

js
function bookingText(name, guests, time = "19:00") {
  return `${name}: ${guests} kishi, soat ${time}`;
}

console.log(bookingText("Malika", 4)); // Malika: 4 kishi, soat 19:00
Yechim
js
// @ts-check

/**
 * Bron haqida bir qatorli matn yasaydi.
 * @param {string} name mehmon ismi
 * @param {number} guests necha kishi
 * @param {string} [time] "SS:DD", standart — "19:00"
 * @returns {string}
 */
function bookingText(name, guests, time = "19:00") {
  return `${name}: ${guests} kishi, soat ${time}`;
}

console.log(bookingText("Malika", 4)); // Malika: 4 kishi, soat 19:00

[time] — kvadrat qavs: ixtiyoriy parametr. Endi bookingText("Malika", "4") deb yozsangiz, VS Code "4" ostiga qizil chiziq tortadi.

2-mashq (o'rta): @typedef va topilgan xato

Quyidagi kodga Order (buyurtma) turini yozing (dish — satr, quantity — son, note — ixtiyoriy satr) va // @ts-check qo'shing. tsc qanday xato topadi? Tuzating.

js
const orders = [
  { dish: "Osh", quantity: 2 },
  { dish: "Manti", quantity: 3, note: "achchiqsiz" },
];

function totalPortions(list) {
  return list.reduce((sum, b) => sum + b.quantty, 0);
}

console.log(totalPortions(orders)); // NaN
Yechim
js
// @ts-check

/**
 * @typedef {object} Order
 * @property {string} dish
 * @property {number} quantity
 * @property {string} [note]
 */

/** @type {Order[]} */
const orders = [
  { dish: "Osh", quantity: 2 },
  { dish: "Manti", quantity: 3, note: "achchiqsiz" },
];

/**
 * @param {Order[]} list
 * @returns {number}
 */
function totalPortions(list) {
  return list.reduce((sum, b) => sum + b.quantity, 0);
}

console.log(totalPortions(orders)); // 5

b.quantty da tsc aytadi: Property 'quantty' does not exist on type 'Order'. Did you mean 'quantity'?. Node esa undefined ni qo'shib, jim NaN berardi. reduce ning sum va b parametrlariga tur yozish shart emas — tsc ularni list turidan o'zi chiqaradi.

3-mashq (qiyin): unknown dan Booking ga

Saqlangan matndan bronni o'qiydigan funksiya yozing. JSON.parse natijasi unknown bo'lsin; shakli to'g'ri bo'lsa — { name, guests }, aks holda null. tsc xatosiz o'tsin.

Ishora: turni qadamma-qadam toraytiring — avval typeof raw === "object" va null emasligi, keyin "name" in raw (in operatori — xususiyat bormi, Obyekt: kalit-qiymat juftliklari), keyin typeof raw.name.

Yechim
js
// @ts-check

/**
 * @typedef {object} Booking
 * @property {string} name
 * @property {number} guests 1 dan 20 gacha
 */

/**
 * Saqlangan matndan bronni o'qiydi; shakli noto'g'ri bo'lsa — null.
 * @param {string} text
 * @returns {Booking | null}
 */
function parseBooking(text) {
  /** @type {unknown} */
  const raw = JSON.parse(text);
  if (typeof raw !== "object" || raw === null) return null;
  if (!("name" in raw) || typeof raw.name !== "string") return null;
  if (!("guests" in raw) || typeof raw.guests !== "number") {
    return null;
  }
  return { name: raw.name, guests: raw.guests };
}

console.log(parseBooking('{"name":"Malika","guests":4}'));
console.log(parseBooking('{"name":"Malika","guests":"4"}')); // null
console.log(parseBooking("null")); // null

Konsolda:

text
{ name: 'Malika', guests: 4 }
null
null

Har if turni bir qadam toraytiradi: object va null emas → "name" in raw bilan name xususiyati bor → typeof bilan u satr. Oxirgi qatorda tsc hamma maydon to'g'ri turda ekanini biladi. Yangi obyekt qaytarilgani ham muhim: raw dagi ortiqcha maydonlar natijaga o'tmaydi (oq ro'yxat g'oyasi).

4-mashq: Vazifalar qadami — JSDoc va // @ts-check

vazifalar ning to'rt sof modulini (DOM'ga bog'lanmaganlarini) tur tekshiruviga ulaymiz.

  • Branch: chore/jsdoc-ts-check
  • Commit: chore: sof modullarga JSDoc turlari va // @ts-check; npm run tip
  1. npm install --save-dev --save-exact typescript@7.0.2; package.json ga "tip": "tsc --noEmit -p jsconfig.json".
  2. jsconfig.json — «jsconfig.json: butun loyiha uchun» bo'limidagi fayl: allowJs, checkJs, noEmit, strict: true, target: es2024, lib: ["esnext", "dom"] (Object.groupBy, Set.prototype.difference, toSorted uchun), module: esnext, moduleResolution: bundler. include — faqat to'rt sof modul: vazifa.js, royxat.js, paket.js, api.js (har birining 1-qatori // @ts-check).
  3. JSDoc: @typedef VazifaMalumoti (vazifa.js), boshqa modullarda /** @import { VazifaMalumoti } from "./vazifa.js" */; @param/@returns hamma funksiyada; @typedef SorovSozlamasi / IchkiSozlama (api.js); tur predikati @returns {qiymat is Record<string, unknown>} (oddiyObyektmi); assertion @returns {asserts malumotlar is VazifaMalumoti[]} (malumotlarniTekshir); @throws {VazifaXatosi}.

Avval faqat 1–2-qadamni bajarib (// @ts-check va jsconfig.json, JSDoc'siz), npm run tip ni ishga tushiring. Keyin JSDoc yozing va haqiqiy xatolarni tuzating.

Yechim

tsc — oldin (// @ts-check va jsconfig.json, JSDoc'siz): strict: true da 73 xato — 63×TS7006 (parametr turi yo'q), 4×TS7031, 2×TS7008 (#vazifalar, #tinglovchilar — any[]), 2×TS7053, 1×TS2339, 1×TS2739. Chiqishdan parcha:

text
assets/js/api.js(55,5): error TS7053: Element implicitly has an 'any' type because expression of type '"Content-Type"' can't be used to index type '{ Accept: string; }'.
assets/js/api.js(56,11): error TS2339: Property 'body' does not exist on type '{ method: string; headers: { Accept: string; }; signal: AbortSignal; }'.
assets/js/royxat.js(37,3): error TS7008: Member '#vazifalar' implicitly has an 'any[]' type.

strict: false da — 1 ta:

text
assets/js/api.js(86,33): error TS2739: Type '{}' is missing the following properties from type '{ kutish?: number; metod?: string; signal: any; tana: any; }': signal, tana

Tarjimasi: "{} turida quyidagi xususiyatlar yetishmaydi: signal, tana". sorovYubor(url, sozlama = {}) dagi bo'sh obyekt sorovniTayyorla ga beriladi, tsc esa uning parametrlari turini destrukturlashdan chiqargan — standart qiymati yo'q signal va tana majburiy bo'lib qolgan.

Haqiqiy xatolar (implicit any emas) va tuzatish:

Xato Sabab Tuzatish Xulq
api.js TS2739 sorovYubor(url, sozlama = {}) sorovniTayyorla({ … }) parametrlari turi destrukturdan chiqarilgan: signal, tana majburiy bo'lib qolgan @typedef SorovSozlamasi / IchkiSozlama — hammasi ixtiyoriy o'zgarmadi
api.js TS7053 sorov.headers["Content-Type"] = …, TS2339 sorov.body = … obyekt literali turi keyin qo'shiladigan xususiyatni bilmaydi /** @type {RequestInit & { headers: Record<string, string> }} */ const sorov o'zgarmadi
royxat.js TS2532 ×2 this.top(id).almashtir(), this.top(id).matnniOzgartir(matn) — "Object is possibly 'undefined'" (JSDoc @returns {Vazifa | undefined} qo'yilgach chiqdi) noma'lum id'da undefined.almashtir() #topYokiXato(id) — throw new TypeError(`Vazifa topilmadi: id ${id}`) xato turi o'sha (TypeError, #35 testi o'zgarmay o'tdi), matni tushunarli; UI bu yo'lga bormaydi. Test endi matnni ham tekshiradi
Xato Sabab Tuzatish Xulq
paket.js TS18046 'v.id' is of type 'unknown' + TS2345 ×2 (v.id < 1, idlar.has/add(v.id)) — vazifaniOl Record<string, unknown> qaytargach Number.isInteger turni toraytirmaydi shartga typeof v.id !== "number" || qo'shildi mantiqan bir xil (Number.isInteger raqam bo'lmaganda baribir false)
api.js tarmoqXatosi(xato) — catch qiymati unknown — const { name } = /** @type {Error} */ (xato); (izoh: fetch faqat Error tashlaydi) bir xil (null bo'lsa ikkalasi ham TypeError)

Jadvallardagi ikki yangi yozuv: RequestInit — fetch ning ikkinchi argumenti (sozlamalar obyekti) turi, u jsconfig.json dagi dom dan keladi. & — "va": RequestInit & { headers: … } — ikkala turning xususiyatlari birga. | "yoki" bo'lsa, & — "ham".

Eng qiziq topilma — royxat.js da. top(id) ga @returns {Vazifa | undefined} yozilishi bilan tsc ikki joyni ko'rsatdi: noma'lum id kelsa, undefined.almashtir() — tushunarsiz TypeError. Tuzatish:

js
  // UI faqat ekrandagi id bilan chaqiradi: noma'lum id — dasturchi
  // xatosi. Avval undefined'dan tushunarsiz TypeError chiqardi
  /** @param {number} id */
  #topYokiXato(id) {
    const vazifa = this.top(id);
    if (vazifa === undefined) {
      throw new TypeError(`Vazifa topilmadi: id ${id}`);
    }
    return vazifa;
  }

  /** @param {number} id */
  almashtir(id) {
    this.#topYokiXato(id).almashtir();
    this.#xabarBer();
  }

Xulq o'zgarmadimi? Xato turi o'sha — TypeError, Birinchi avtomatik test darsidagi qotiruvchi test (assert.throws(..., TypeError)) o'zgarmay o'tdi. Faqat matn tushunarli bo'ldi, test endi uni ham tekshiradi:

js
  test("noma'lum id — TypeError, sababi aytiladi", () => {
    const xato = {
      name: "TypeError",
      message: "Vazifa topilmadi: id 99",
    };
    assert.throws(() => yangiRoyxat().almashtir(99), xato);
    assert.throws(() => yangiRoyxat().matnniOzgartir(99, "A"), xato);
  });

paket.js dagi tuzatish — «Number.isInteger tur toraytiradi deb o'ylash» xatosining aynan o'zi:

js
    if (
      typeof v.id !== "number" ||
      !Number.isInteger(v.id) ||
      v.id < 1 ||
      idlar.has(v.id)
    ) {

Keyin: npm run tip — chiqishsiz, exit 0. npm test — 59/59, lint, format:check toza.

TEXNIK-QARZ.md: 6-qator "to'landi (12/#39)" — chizib qo'yildi, yonida: // @ts-check topdi, endi TypeError: Vazifa topilmadi: id N. Yangi 10-qator (9-qator — nomlash qarzi, u Legacy kod va texnik qarz darsidan beri bor) ikki narsani yozadi:

  • // @ts-check faqat 4 modulda (vazifa, royxat, paket, api); qolgan oltitasi va testlar tekshirilmaydi;
  • javobniOqi server JSON'ini any deb qaytaradi — shaklini paketniOqi ish vaqtida tekshiradi.

Bu Legacy kod va texnik qarz darsidagi qoida: qarz to'landi va ro'yxatdan ko'rinib turibdi, yangi qarz esa yashirilmadi.

README v3.1 ga yangilandi (npm install, lint/format/tip, TEXNIK-QARZ.md havolasi). .gitignore: node_modules/.

bash
git switch -c chore/jsdoc-ts-check
npm install --save-dev --save-exact typescript@7.0.2
# jsconfig.json, // @ts-check, JSDoc, tuzatishlar
npm run tip && npm test && npm run lint && npm run format:check
git add .
git commit -m "chore: sof modullarga JSDoc turlari va // @ts-check; \
npm run tip"
git push -u origin chore/jsdoc-ts-check
gh pr create --fill
gh pr merge --merge

Shu qadam bilan vazifalar v3.1 tayyor: to'rtta tekshiruv (npm test, npm run lint, npm run format:check, npm run tip) va brauzer ssenariysi 45/45 — ilova xulqi #08 dagi bilan bir xil.

9. Real ishda

  • Katta JavaScript loyihalarida JSDoc + checkJs — TypeScript'ga o'tishning birinchi bosqichi: fayllar .js bo'lib qoladi, tekshiruv esa modulma-modul kengayadi.
  • Kutubxonalar hujjati. npm'dagi ko'p paketlarning hujjat sayti JSDoc izohlaridan avtomatik yasaladi. Siz VS Code'da ko'rgan paket maslahatlari ham shunday izohlardan (yoki .d.ts tur fayllaridan) keladi.
  • CI'da npm run tip ham lint va test qatorida turadi — tur xatosi bilan PR birlashtirilmaydi.
  • TypeScript bugun frontend va Node vakansiyalarining katta qismida talab qilinadi. Nega TypeScript darsidan boshlab 15-qism shu tilga bag'ishlangan; bugungi @typedef u yerda type va interface ga aylanadi.
  • Intervyu: "any va unknown farqi?", "Narrowing nima?", "JSDoc bilan TypeScript'siz tur tekshirsa bo'ladimi?" — tez-tez so'raladi.

Xulosa

  • JSDoc — /** … */ dagi turli izoh: @param {tur} nom, @returns, @type, @typedef + @property, @import. U kodni o'zgartirmaydi.
  • // @ts-check (fayl boshida) VS Code'da tekshiruvni yoqadi; tsc --noEmit -p jsconfig.json — terminal va CI uchun. Kod ishga tushmasdan "35 000" kabi noto'g'ri turni topadi.
  • strict da tur yozilmagan parametr — TS7006; mavjud loyihada birinchi natija katta bo'ladi, lekin haqiqiy topilmalar ozchilik.
  • undefined bo'lishi mumkin bo'lgan qiymat va unknown avval tekshiriladi — bu turni toraytirish (if, predikat yoki asserts). Cast (/** @type {…} */ (x)) — qavs bilan va kam.
  • JSDoc — TypeScript'ning o'sha tekshiruvchisi, faqat izohda. 15-qismda turlar kodning o'ziga ko'chadi.

Keyingi dars: JavaScript'ning mashhur tuzoqlari — butun kurs davomida uchragan eng xavfli tuzoqlarni bitta ro'yxatga yig'amiz va qaysi birini qaysi vosita ushlashini ko'ramiz.

Manbalar

  • TypeScript hujjatlari: "JSDoc Reference", "Type Checking JavaScript Files", "What is a jsconfig.json" — typescriptlang.org/docs
  • TypeScript blogi: "A 10x Faster TypeScript" (2025-03) — devblogs.microsoft.com/typescript
  • JSDoc — jsdoc.app
  • VS Code hujjatlari: "JavaScript type checking" — code.visualstudio.com/docs/languages/javascript
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JSDoc va // @ts-check: oddiy JavaScript'da turlarni tekshirish — IlmHamroh