IlmHamroh
JavaScript Full-stack/15-qism. TypeScript45/47-dars20 daqiqa
Mundarija (29)

JavaScript'dan TypeScript'ga ko'chish: allowJs, checkJs va fayl-fayl o'tish

Qisqacha: Katta JavaScript loyihani bir kunda TypeScript'ga o'tkazish shart emas. tsconfig.json da "allowJs": true — .js va .ts fayllar yonma-yon yashaydi va birga yig'iladi. "checkJs": true yoki fayl boshidagi // @ts-check — JavaScript ham JSDoc izohlari bo'yicha tekshiriladi. Keyin fayllar birma-bir .ts ga o'tadi: avval hech narsaga tayanmaydigan "barg" modullar, oxirida DOM va kirish fayli. Hozircha tuzatib bo'lmaydigan joy — // @ts-expect-error bilan belgilanadi. Oxirida allowJs o'chadi.

Bu darsda

  • allowJs, checkJs va // @ts-check / // @ts-nocheck farqini bilasiz.
  • JSDoc turlarini TypeScript yozuviga aylantirasiz.
  • Modullarni qaysi tartibda ko'chirish kerakligini bog'liqlik grafidan aniqlaysiz.
  • strict ni bosqichma-bosqich yoqasiz, @ts-expect-error va @ts-ignore farqini bilasiz.
  • vazifalar ko'chishini yakunlaysiz: oxirgi modullar .ts, allowJs o'chadi — 12 qadamda topilgan xatolarni jamlaysiz.

Oldin bilishingiz kerak: JSDoc va // @ts-check, tsconfig.json chuqur, Strict bayroqlar oilasi, Build: tsc, bundler'lar va tsgo, Async kod va xatolarni tiplash.

1. Nega bu kerak?

O'rnatish darsida vazifalar ning 17 modulida checkJs ni bir vaqtda yoqib ko'rgan edik: 249 xato, 8 faylda. Tasavvur qiling: shu 249 tani bitta commit'da tuzatish. Bir haftalik ish, yuzlab o'zgargan qator, kod sharhida hech kim tekshira olmaydigan PR. Bu vaqtda jamoa boshqa ish qila olmaydi — har o'zgarish ko'chish bilan to'qnashadi.

Haqiqiy kompaniyalar ham shu muammoga duch keladi: Airbnb, Slack kabi jamoalar katta JavaScript kodini TypeScript'ga bosqichma-bosqich, oylar davomida o'tkazgan. Sir — TypeScript'ning o'zi bunga imkon beradi: JavaScript va TypeScript fayllar bitta loyihada yonma-yon yashay oladi.

Hayotiy o'xshatish: «Bahor» oshxonasini ta'mirlash. Hammasini birdan buzib, bir oy yopib qo'yish mumkin. Yoki har hafta bitta burchakni ta'mirlab, oshxonani ishlatib turish mumkin. Ikkinchi yo'l sekinroq, lekin mijozlar hech qachon "yopiq" degan yozuvni ko'rmaydi.

2. allowJs va checkJs

2.1 Ikki bayroq — ikki ish

Bayroq Nima qiladi
allowJs: true .js fayllar dasturga kiradi: .ts ulardan import qila oladi, tsc ularni outDir ga ko'chiradi
checkJs: true .js fayllar ham tekshiriladi (JSDoc va tur chiqarish bo'yicha)
// @ts-check faqat shu .js fayl tekshiriladi (checkJs siz ham)
// @ts-nocheck shu fayl tekshirilmaydi (checkJs bo'lsa ham)

allowJs siz .ts fayl .js ni import qilsa, tsc uni ko'rmaydi va tur ma'lumoti yo'q bo'ladi. allowJs bilan esa tsc JavaScript'ni o'qiydi va turlarni o'zi chiqaradi — xuddi .ts dagidek.

vazifalar aynan shunday yo'l tutdi:

  • 12-qism (JSDoc va // @ts-check) — 9 modulning tepasida // @ts-check, tsc --noEmit.
  • 15-qism, o'rnatish — tsconfig.json: allowJs: true, checkJs: false. Hamma .js dist/ ga yig'iladi, tekshiruv — faqat // @ts-check li fayllarda.
  • Keyingi qadamlar — fayllar birma-bir .ts ga.
  • Bugun — oxirgi fayllar, allowJs o'chadi.

2.2 JavaScript ham tekshiriladi — JSDoc bo'yicha

checkJs bilan .js fayldagi JSDoc izohlari — turlar. JSDoc darsida buni ko'rgansiz. Ko'chishda bu muhim: har JSDoc izohi — tayyor TypeScript turi, uni yo'qotmay, ko'chirish kerak.

JSDoc (.js) TypeScript (.ts)
@param {number} price (price: number)
@returns {string} (): string
@typedef {{id: number}} Order type Order = { id: number }
@template T <T>
/** @type {Order} */ (x) x as Order
@import { Order } from "./t.ts" import type { Order } from "./t.ts"

Oxirgi ikki qatorga e'tibor bering. /** @type {X} */ (qiymat) — JSDoc'dagi assertion (qavslar majburiy). Ko'chishda uni as ga emas, imkon bo'lsa tekshiruvga aylantiring (TypeScript va DOM darsidagi instanceof). vazifalar da klasslar qadamida prefiks-daraxti dagi shunday assertion while (element !== undefined) tekshiruviga aylandi.

2.3 JavaScript'da hamma parametr ixtiyoriy

Bitta nozik farq bor. .js faylda JSDoc'siz parametrlar ixtiyoriy hisoblanadi: JavaScript'da funksiyani kamroq argument bilan chaqirish odatiy. Shuning uchun checkJs bilan ham withService(sum) (ikkinchi argument unutilgan) — xato emas. .ts da esa:

ts
function withService(sum: number, rate: number): number {
  return Math.round(sum * (1 + rate));
}
console.log(withService(70000));

Kompilyator:

text
TS2554: Expected 2 arguments, but got 1.

TypeScript aytyapti: "2 ta argument kutilgan edi, 1 ta berildi".

JavaScript'da bu chaqiruv xatosiz NaN berardi: 1 + undefined. Bu farqni 3-mashqda haqiqiy xatoda ko'rasiz: fayl .ts ga o'tgan zahoti yashirin bug ochiladi.

Tekshirib ko'ring: allowJs: true, checkJs: false va .js faylning birinchi qatorida // @ts-check bor. Bu fayl tekshiriladimi?

Javob

Ha. // @ts-check — fayl darajasidagi "tekshir" belgisi, u checkJs: false ni shu fayl uchun bekor qiladi. Teskarisi ham bor: checkJs: true bo'lsa, // @ts-nocheck faylni tekshiruvdan chiqaradi. Bu ikki izoh ko'chish paytida "qaysi fayl tayyor" degan belgi bo'lib xizmat qiladi.

3. Fayl-fayl ko'chirish tartibi

3.1 Barglardan ildizga

Qaysi fayldan boshlash kerak? Javob — modullarning import grafidan (Modul semantikasi). Barg (leaf) modul — hech narsani import qilmaydigan yoki faqat turlarni import qiladigan modul. Uni birinchi ko'chirsangiz, unga tayangan hamma fayl darhol aniq turlarni oladi. Kirish fayli (asosiy.js) esa hamma narsani import qiladi — u oxirida.

vazifalar ko'chishi aynan shu tartibda bo'ldi:

flowchart TB
  A["turlar.ts<br/>faqat turlar"] --> B["sinxron, holat,<br/>saqlash, marshrut"]
  B --> C["vazifa, royxat,<br/>prefiks-daraxti"]
  C --> D["qidiruv, saralash,<br/>taymer, api"]
  D --> E["render, asosiy,<br/>tema-tanlash, fayl"]
  E --> F["paket, olchov, tema<br/>allowJs o'chadi"]

Sxemani pastga qarab o'qing: har qavat oldingilariga tayanadi. Ba'zi modulni ko'chirish hozircha imkonsiz bo'lsa (masalan, boshqa jamoaning ichki kutubxonasi), uning yoniga .d.ts yozish mumkin (Declaration fayllari): kod JavaScript'da qoladi, lekin unga tayangan .ts fayllar aniq turlarni oladi. vazifalar dagi vendor/web-vitals.d.ts — shunday fayl. Eng ko'p xato oxirgidan oldingi qavatda — DOM modullarida (219 ta): ular document dan kelgan null lar bilan to'la (TypeScript va DOM).

3.2 Har qadam — bir xil sikl

Har modul uchun bir xil besh qadam:

  1. git mv fayl.js fayl.ts — tarix saqlanadi, git buni "nomi o'zgardi" deb ko'radi.
  2. npm run tip — xatolarni sanang. Ular sizga "nima qilish kerak" ro'yxatini beradi.
  3. Turlarni yozing: avval parametrlar va eksport funksiyalar natijasi (TS7006 ko'pincha eng ko'p), keyin null va toraytirish.
  4. npm test — xulq o'zgarmaganini testlar tasdiqlaydi. Ko'chish — xulqni o'zgartirmaydigan qayta tuzish (refactoring).
  5. Bitta commit, bitta PR. Kichik PR'ni tekshirish oson.

vazifalar da har qadamda fayl nomi o'zgartirilganda (turlar yozilmasdan) shuncha xato chiqdi:

vazifalar: fayl nomi .ts bo'lganda tsc xatolari
  • holat, saqlash, marshrut29 xato
  • 3 klass moduli53 xato
  • qidiruv, saralash, taymer34 xato
  • api33 xato
  • 4 DOM moduli219 xato
  • paket10 xato
  • olchov, tema5 xato

Manba: O'lchandi: tsc 7.0.2 --noEmit, vazifalar v4.1 → v5 ko'chishi, har qadam holati, 2026-10-06

Jami 383 ta — boshidagi bir martalik o'lchovdan (249) ko'p. Sabab: .ts da qoidalar .js dagidan qattiqroq va qadamlar davomida qat'iy bayroqlar qo'shilib bordi. Lekin har qadam — bir kunlik ish. Va har qadamdan keyin npm test 137 (keyin 143) testdan o'tdi, 159 brauzer tekshiruvi — 159/159.

3.3 Strict'ni ham bosqichma-bosqich

Ko'chishning boshida strict ni o'chiq qoldirish mumkin: xatolar ancha kam. vazifalar da checkJs bilan: strict — 249, strict siz — 40. Ko'p jamoalar shunday yo'l tutadi:

  1. strict: false bilan hamma faylni .ts ga o'tkazish.
  2. Bayroqlarni birma-bir yoqish: noImplicitAny, keyin strictNullChecks (eng ko'p xato beradigani), keyin qolganlari (Strict bayroqlar oilasi).

vazifalar boshqa yo'lni tanladi: strict 12-qismdan beri yoqiq, fayllar kichik guruhlarda. Ikkalasi ham to'g'ri — loyiha hajmiga qarab. Yuz minglab qatorli loyihada birinchisi; kichigida ikkinchisi tezroq natija beradi.

Tekshirib ko'ring: Nega asosiy.js ni birinchi bo'lib .ts ga o'tkazish noqulay?

Javob

asosiy.js hamma modulni import qiladi. Ular hali .js bo'lsa, ularning turlari JSDoc'dan yoki tur chiqarishdan keladi — ko'pincha any. Natijada asosiy.ts dagi xatolar soni katta, turlar esa zaif bo'ladi, va har barg modul ko'chganda asosiy.ts ni qayta tuzatish kerak. Barglardan boshlasangiz, har modul o'zidan oldingilarning tayyor turlarini oladi.

4. Hozircha tuzatib bo'lmaydigan joy: @ts-expect-error

4.1 @ts-expect-error — "bu yerda xato bor, bilaman"

Ba'zan xato aniq, lekin tuzatish boshqa modulning ko'chishini kutadi. Butun faylni // @ts-nocheck qilish o'rniga bitta qatorni belgilaysiz:

ts
function priceOf(dish: "osh" | "manti"): number {
  return dish === "osh" ? 35000 : 30000;
}

// @ts-expect-error — somsa menyuga 16-oktabrda qo'shiladi
console.log(priceOf("somsa")); // 30000

@ts-expect-error keyingi qatordagi xatoni o'chiradi. Izohda nega va qachon yozing — bu qarz, uni keyin qaytarasiz. Ishlash paytida esa xato baribir bor: "somsa" uchun 30000 — noto'g'ri narx.

Uning eng foydali xususiyati: xato yo'qolsa, direktivaning o'zi xato beradi:

ts
function priceOf(dish: "osh" | "manti" | "somsa"): number {
  return dish === "osh" ? 35000 : 30000;
}

// @ts-expect-error — somsa menyuga 16-oktabrda qo'shiladi
console.log(priceOf("somsa"));

Kompilyator:

text
TS2578: Unused '@ts-expect-error' directive.

Tarjimasi: "ishlatilmagan @ts-expect-error direktivasi". Somsa turga qo'shildi, xato yo'qoldi — tsc "endi bu izohni olib tashla" deydi. Qarz o'z-o'zidan ko'rinib qoladi.

4.2 @ts-ignore — jim o'chirish

Eski // @ts-ignore ham xatoni o'chiradi, lekin xato yo'qolganda hech narsa demaydi. Yillar o'tib kodda ma'nosiz @ts-ignore lar qoladi — va ular ostidagi qatorga keyin qo'shilgan yangi xatoni ham jimgina yashiradi. Qoida: faqat @ts-expect-error, doim izoh bilan. typescript-eslint'ning ban-ts-comment qoidasi (recommended ichida) @ts-ignore ni taqiqlaydi va @ts-expect-error ga izoh talab qiladi.

4.3 any — ko'chishning eng xavfli "yechimi"

Xatoni tez yo'qotish uchun : any yozish oson: function total(dishes: any). Lekin any yuqumli — u tegib o'tgan har qiymat ham tekshiruvsiz bo'ladi (any va unknown). Ko'chish paytidagi any — "keyin tuzataman" va'dasi, va u ko'pincha bajarilmaydi. Yaxshiroq yo'llar: aniq tur, unknown + tekshiruv, yoki vaqtincha @ts-expect-error (u hech bo'lmasa o'zini ko'rsatadi). vazifalar da no-explicit-any ESLint qoidasi yoqiq — bitta ham any yo'q.

5. ESLint'ni TypeScript bilan ulash

Tur annotatsiyasi darsida va'da qilgan edik: ESLint'ni TypeScript bilan ulash shu yerda. vazifalar da bu Obyekt turlari qadamida qilingan: typescript-eslint paketi (8.71.1).

js
// eslint.config.js (vazifalar, qisqartirildi)
import js from "@eslint/js";
import tseslint from "typescript-eslint";

export default defineConfig([
  js.configs.recommended,
  {
    files: ["**/*.ts"],
    extends: [tseslint.configs.recommended],
  },
]);

tseslint.configs.recommended — .ts fayllarni o'qiydigan tahlilchi (parser) va tavsiya etilgan qoidalar: no-explicit-any, no-unused-vars, ban-ts-comment va boshqalar. Ko'chish paytida .js va .ts fayllar bitta konfiguratsiyada yashaydi: js.configs.recommended — hammasiga, typescript-eslint — faqat **/*.ts ga.

Yana bir to'plam — tseslint.configs.stylistic. Unda o'sha va'da qilingan no-inferrable-types bor: const count: number = 0 kabi ortiqcha turni ko'rsatadi (TypeScript 0 dan o'zi number chiqaradi). Turli qoidalar (Async kod qadamidagi no-floating-promises) esa projectService bilan alohida yoqiladi — ular sekinroq, lekin turlarni biladi.

6. Ko'p uchraydigan xatolar

6.1 Hammasini bitta PR'da ko'chirish

Tuzatish: kichik qadamlar, har biri — testlardan o'tgan alohida PR.

6.2 JSDoc turlarini tashlab yuborish

Fayl .ts ga o'tdi, JSDoc'dagi @param {…} o'chirildi, lekin turlar yozilmadi — TS7006. Tuzatish: har @param turini parametr yoniga ko'chiring, tavsif qismi oddiy izoh bo'lib qolishi mumkin.

6.3 TS2578: Unused '@ts-expect-error' directive.

Bu yaxshi xabar: qarz o'z-o'zidan to'landi. Tuzatish: izohni o'chiring.

6.4 @ts-ignore va any bilan "tez ko'chish"

Tuzatish: @ts-expect-error + izoh; any o'rniga unknown yoki aniq tur.

6.5 Ko'chish paytida xulqni ham o'zgartirish

"Bir yo'la shu bug'ni ham tuzataman". Natija — PR'da ikki xil o'zgarish, testlar qizil bo'lsa, sababini topish qiyin. Tuzatish: avval ko'chiring (xulq o'zgarmasin), keyin alohida PR'da tuzating. vazifalar dagi har xulq farqi QADAM izohida alohida yozilgan.

7. Mashqlar

1-mashq (oson): Direktivalar

// @ts-expect-error ostidagi qatorda xato yo'q bo'lsa, tsc qaysi kodli xato beradi? TS[:2578]. Xato bor bo'lganda // @ts-ignore ning @ts-expect-error dan farqi bormi (ha/yo'q)? [:yo'q].

Yechim

TS2578: Unused '@ts-expect-error' directive. Xato bor bo'lganda ikkalasi bir xil — xatoni o'chiradi. Farq xato yo'qolganda chiqadi: @ts-expect-error aytadi, @ts-ignore jim qoladi. Shuning uchun @ts-ignore ishlatilmaydi.

2-mashq (o'rta): JSDoc'dan TypeScript'ga

12-qismdagi uslubda yozilgan funksiyani .ts ga ko'chiring:

js
/**
 * @typedef {{ guest: string, people: number }} Booking
 */

/**
 * Stol tanlash: odamlar soniga mos eng kichik stol
 * @param {Booking} booking
 * @param {number[]} tables stollardagi o'rinlar
 * @returns {number | null} stol o'lchami yoki null
 */
export function pickTable(booking, tables) {
  const fitting = tables.filter((size) => size >= booking.people);
  return fitting.length ? Math.min(...fitting) : null;
}

Ishora: @typedef → type; tables ni funksiya o'zgartirmaydi — readonly (Massiv va tuple).

Yechim
ts
export type Booking = { guest: string; people: number };

// Stol tanlash: odamlar soniga mos eng kichik stol
// tables — stollardagi o'rinlar; mos stol yo'q bo'lsa — null
export function pickTable(
  booking: Booking,
  tables: readonly number[],
): number | null {
  const fitting = tables.filter((size) => size >= booking.people);
  return fitting.length ? Math.min(...fitting) : null;
}

const booking = { guest: "Dilshod aka", people: 5 };
console.log(pickTable(booking, [2, 4, 6, 8])); // 6
console.log(pickTable(booking, [2, 4])); // null

@param lardagi tavsiflar oddiy izohga ko'chdi, turlar — parametr yoniga. @typedef — export type: endi boshqa fayllar uni import type { Booking } bilan oladi. readonly number[] — JSDoc'da yo'q edi, ko'chish paytida qo'shilgan aniqlik (xulq o'zgarmaydi).

3-mashq (qiyin): Amaliy tajriba — uch faylli loyihani ko'chirish

kurs/mashqlar/15/45-kochish/ — uch JavaScript fayl. kassa.js ni ishga tushiring: Jami: NaN so'm. Bug bor, lekin qayerda?

js
// narx.js — «Bahor» narxlari
export const PRICES = {
  osh: 35000,
  manti: 30000,
  lagmon: 28000,
  choy: 5000,
};

export function priceOf(dish) {
  return PRICES[dish];
}
js
// buyurtma.js — buyurtma summasi
import { priceOf } from "./narx.js";

export function total(dishes) {
  return dishes.reduce((sum, dish) => sum + priceOf(dish), 0);
}

export function withService(sum, rate) {
  return Math.round(sum * (1 + rate));
}
js
// kassa.js — chek chiqarish
import { total, withService } from "./buyurtma.js";

const order = ["osh", "choy", "somsa"];
const sum = total(order);
console.log(`Jami: ${withService(sum)} so'm`);
  1. 45-kochish/tsconfig.json: allowJs, checkJs, noEmit, strict, module: "nodenext", types: ["node"] (4-qadamdagi test node:test ni import qiladi — usiz TS2591), allowImportingTsExtensions. (Ildizdagi tsconfig.json ning exclude iga "45-kochish" ni qo'shing.) npx tsc -p 45-kochish --pretty false — xatolarni sanang. strict: false bilan-chi?
  2. Barg modul — narx.js → narx.ts. Taom nomlari turi: keyof typeof PRICES. Xatolarni qayta sanang.
  3. buyurtma.js → buyurtma.ts. Endi tsc nimani topadi?
  4. kassa.js → kassa.ts, buglarni tuzating (xizmat haqi — 10%), buyurtma.test.ts yozing.
Yechim

1-qadam. strict bilan — 7 xato: TS7006 ×6 (parametr turi yo'q) va bitta TS7053. strict: false bilan — 0. Ikkala holatda ham haqiqiy bug ko'rinmaydi: JavaScript'da parametrlar ixtiyoriy va turlar any.

2-qadam. narx.ts:

ts
// narx.ts — «Bahor» narxlari
export const PRICES = {
  osh: 35000,
  manti: 30000,
  lagmon: 28000,
  choy: 5000,
};

export type DishName = keyof typeof PRICES;

export function priceOf(dish: DishName): number {
  return PRICES[dish];
}

console.log(priceOf("lagmon")); // 28000

keyof typeof PRICES — "osh" | "manti" | "lagmon" | "choy" (keyof va typeof): obyektga yangi taom qo'shilsa, tur o'zi kengayadi. buyurtma.js dagi import yo'li ./narx.ts bo'ladi. Xatolar — 5 (hammasi buyurtma.js da, TS7006). Oxirgi qator (console.log) — darsda sinash uchun, mashq faylida u yo'q: aks holda kassa.ts ishga tushganda chek oldidan ortiqcha 28000 chiqardi.

3-qadam. buyurtma.ts:

ts
// buyurtma.ts — buyurtma summasi
import { priceOf, type DishName } from "./narx.ts";

export function total(dishes: readonly DishName[]): number {
  return dishes.reduce((sum, dish) => sum + priceOf(dish), 0);
}

export function withService(sum: number, rate: number): number {
  return Math.round(sum * (1 + rate));
}

Xatolar — 2, va ikkalasi kassa.js da, garchi u hali JavaScript bo'lsa ham:

text
45-kochish/kassa.js(5,19): error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'readonly ("choy" | "lagmon" | "manti" | "osh")[]'.
  Type 'string' is not assignable to type '"choy" | "lagmon" | "manti" | "osh"'.
45-kochish/kassa.js(6,22): error TS2554: Expected 2 arguments, but got 1.

Mana NaN ning ikki sababi: menyuda yo'q "somsa" (priceOf — undefined) va unutilgan rate (1 + undefined — NaN). kassa.js ga hech kim tegmadi — u import qilgan funksiyalar endi aniq turga ega, va checkJs chaqiruvlarni shu turlarga solishtirdi. Bu ko'chishning eng yoqimli lahzasi: yashirin buglar o'zi chiqib keladi.

4-qadam. kassa.ts:

ts
// kassa.ts — chek chiqarish
import { total, withService } from "./buyurtma.ts";
import type { DishName } from "./narx.ts";

const SERVICE_RATE = 0.1;
const order: DishName[] = ["osh", "choy", "manti"];
const sum = total(order);
console.log(`Jami: ${withService(sum, SERVICE_RATE)} so'm`);

node 45-kochish/kassa.ts — Jami: 77000 so'm. order ga DishName[] turi yozildi: endi "somsa" qo'shsangiz, tsc shu qatorni ko'rsatadi. Endi .js fayl qolmadi — allowJs va checkJs ni o'chiring. Yakuniy tsconfig.json da beshta qator qoladi: noEmit, strict, module, types, allowImportingTsExtensions.

buyurtma.test.ts:

ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { total, withService } from "./buyurtma.ts";

test("total: taomlar narxi yig'indisi", () => {
  assert.equal(total(["osh", "choy"]), 40000);
  assert.equal(total([]), 0);
});

test("withService: 10% va yaxlitlash", () => {
  assert.equal(withService(70000, 0.1), 77000);
  assert.equal(withService(28005, 0.1), 30806);
});

npx tsc -p 45-kochish — toza, node --test 45-kochish/buyurtma.test.ts — bizda (Node 24.21.0):

text
✔ total: taomlar narxi yig'indisi (2.2693ms)
✔ withService: 10% va yaxlitlash (0.7217ms)
ℹ tests 2
ℹ suites 0
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 312.9662

Xatolar yo'li: 7 → 5 → 2 → 0. XATOLAR.md ga TS2578 va TS2554 (JS'dan ko'chganda ochiladigan) ni qo'shing:

bash
git add 15/45-kochish 15/tsconfig.json 15/XATOLAR.md
git commit -m "15/45: uch fayl .ts ga — 7 → 0 xato, 2 bug"

4-mashq: Vazifalar qadami — ko'chish yakuni

Ikkita JavaScript modul qoldi: olchov.js (Web Vitals) va tema.js (sahifa chizilishidan oldin temani qo'llaydigan skript). Ular ko'chgach, allowJs kerak emas.

  • Branch: chore/ts-tugadi
  • Commit: chore: hamma modul .ts, allowJs o'chirildi; hujjatlar v5, tanasi: olchov.ts, tema.ts; README, AGENTS, TEXNIK-QARZ v5; sw VERSIYA v5-11
  1. olchov.js → olchov.ts, tema.js → tema.ts; asosiy.ts da import("./olchov.ts").
  2. tsconfig.json dan allowJs va checkJs ni olib tashlang.
  3. sw.js ni nima qilish kerakligini o'lchang (checkJs + lib: ["webworker"]).
  4. Hujjatlar: README, AGENTS.md, TEXNIK-QARZ — v5.
  5. Toza o'rnatishda tekshiring: rm -rf node_modules dist && npm ci.
Yechim

1-qadam: olchov.ts — nomi o'zgartirilganda 5 xato: TS7031 ×3 (destructuring parametrda — { name, value, rating } — tur yo'q), TS7053 va TS7006. Turlar web-vitals paketidan keladi — Build qadamidagi vendor/web-vitals.d.ts orqali:

ts
// Turlar — vendor/web-vitals.d.ts orqali npm paketidan
import type { Metric } from "./vendor/web-vitals.js";

const BAHOLAR: Readonly<Record<Metric["rating"], string>> =
  Object.freeze({
    good: "yaxshi",
    "needs-improvement": "yaxshilash kerak",
    poor: "yomon",
  });

// Pick: funksiyaga butun Metric emas, uch maydon yetadi (testda ham)
type Olchov = Pick<Metric, "name" | "value" | "rating">;

// CLS — o'lchovsiz son (siljish ulushi), qolganlari — millisekund
export function olchovMatni({ name, value, rating }: Olchov): string {
  • Metric["rating"] — indexed access: kutubxonadagi "good" | "needs-improvement" | "poor". Record bilan — har baho uchun matn shart: kutubxona yangi baho qo'shsa, tsc aytadi.
  • Pick<Metric, …> — Utility types: test butun Metric obyektini yasamasdan, uch maydonli obyekt beradi.

tema.ts — 0 xato. Bu oddiy skript: import/export yo'q, index.html da <script src="…/tema.js"> (modul emas — kechiktirilmasligi kerak). tsc uni skript deb biladi va dist/assets/js/tema.js ga "use strict"; qo'shib chiqaradi, export {} qo'shmaydi — tekshirildi.

2-qadam: tsconfig.json. Ikki qator olib tashlandi, izoh yangilandi:

jsonc
{
  // Ko'chish tugadi (15/#45): assets/js da faqat .ts (va .d.ts) —
  // allowJs o'chirildi, JS fayl kompilyatsiyaga kirmaydi
  "compilerOptions": {
    "strict": true,

assets/js da endi: 17 modul + turlar.ts + tema.ts (hammasi .ts) va trusted-types.d.ts.

3-qadam: sw.js JavaScript qoladi. O'lchov: checkJs + lib: ["webworker"] — 9 xato. self — WorkerGlobalScope deb ko'rinadi (ServiceWorkerGlobalScope emas), event.waitUntil va respondWith — oddiy Event da yo'q. Service Worker — ES modul emas (export {} qo'shilsa, ro'yxatdan o'tmaydi), unga alohida lib va tsconfig kerak. Qaror: hozircha JS, TEXNIK-QARZ 23 — PWA mavzusida (21-qism) qaytamiz. Ko'chishda hamma narsani .ts qilish maqsad emas — maqsad tekshiriladigan, xavfsiz kod.

4–5-qadamlar. README ("Build" bo'limi, modullar .ts, kod qoidalari), AGENTS.md (TS qoidalari: import type, .ts yo'l, any/as taqiqi, unknown, Natija, never; 143 test), TEXNIK-QARZ v5 (10-qator to'landi, yangilari: 23 — sw.js, 24 — ikki TypeScript, 25 — build faqat tsc, 26 — tekshiruv qo'lda). Toza o'rnatish: rm -rf node_modules dist && npm ci → npx tsc --version → Version 7.0.2.

Natija: npm test — 143/143 (33 suite), test:tarmoq 2/2. tip, lint, format:check — toza. Brauzer (dist/) — 159/159. Lighthouse 13.5.0 (mobil) — 100 / 100 / 100 / 100. dist/assets/js — 81 095 bayt (#02 da JavaScript manbaning o'zi — 77 748; +4 % — yangi tekshiruv kodi va izohlar, turlar esa o'chdi). Diff: 13 fayl, +184 −110.

bash
git switch -c chore/ts-tugadi
git mv assets/js/olchov.js assets/js/olchov.ts
git mv assets/js/tema.js assets/js/tema.ts
# tsconfig.json, asosiy.ts importi, README, AGENTS, TEXNIK-QARZ
npm run build && npm test && npm run tip
npm run lint && npm run format:check
git add .
git commit -m "chore: hamma modul .ts, allowJs o'chirildi; hujjatlar v5" \
  -m "olchov.ts, tema.ts; README, AGENTS, TEXNIK-QARZ v5; sw VERSIYA v5-11"
git push -u origin chore/ts-tugadi
gh pr create --fill
gh pr merge --merge

Butun ko'chish — 12 qadam, raqamlarda. Biz (tsc 7.0.2 ning haqiqiy chiqishi bilan) har qadamda shuncha xato topdik:

Qadam Nima Xato
O'rnatish checkJs hammaga (o'lchov) 249 / 40 strict siz
type va interface interface VazifaMalumoti 1
Discriminated union case'siz Saralash 1
null va undefined 3 modul / strictNullChecks 29 / 9
Klasslar 3 klass moduli 53
Generic cheklovlar 3 generic modul 34
Utility types api.ts 33
Strict bayroqlar noUncheckedIndexedAccess 2
TypeScript va DOM 4 DOM moduli 219
API ma'lumotlari paket.ts 10
Async kod ESLint Promise qoidalari 13 (1 haqiqiy)
Bu dars olchov, tema / sw.js 5 / 9

Ularning ko'pchiligi — TS7006 (tur yozilmagan) va TS18047 (null bo'lishi mumkin): "TypeScript'ga turni ayting" va "null ni tekshiring". Lekin orasida haqiqiy buglar ham bor edi: searchParams.get() ning null i, indeks tekshiruvi, ushlanmagan import() rad etilishi, server javobidagi versiya yo'qligi. Ilova xulqi esa hech bir qadamda buzilmadi — 137 eski test va 159 brauzer tekshiruvi har safar o'tdi.

8. Real ishda

  • Ko'chish loyihalari — ishga kirganingizda eng ko'p uchraydigan vazifalardan biri: "eski JS modulni TS ga o'tkaz". Bugungi tartib (barglardan, kichik PR'lar, testlar) — aynan shu ish.
  • Avtomatik vositalar — Airbnb'ning ts-migrate kabi vositalar fayllarni ommaviy .ts ga o'tkazadi va xatolarni @ts-expect-error bilan belgilab chiqadi. Keyin jamoa ularni birma-bir tuzatadi. Bu katta loyihada boshlang'ich nuqta, tayyor natija emas.
  • Kutubxonalar — ko'p npm paketlar hali JavaScript'da, turlari .d.ts yoki @types da (Uchinchi tomon kutubxonalarini tiplash). allowJs va JSDoc — ularning ichki ishida ham uchraydi (masalan, Svelte o'z manbasini JSDoc bilan yozadi).
  • Intervyu: "Katta JS loyihani TS'ga qanday ko'chirasiz?", "allowJs va checkJs farqi?", "@ts-ignore va @ts-expect-error farqi?".

Xulosa

  • allowJs — .js va .ts yonma-yon; checkJs yoki // @ts-check — JavaScript ham JSDoc bo'yicha tekshiriladi.
  • JSDoc turlari — tayyor TypeScript turlari: @param → parametr turi, @typedef → type, @template → <T>.
  • Tartib — barglardan ildizga; har qadam: git mv, tip, turlar, test, bitta PR. Ko'chish xulqni o'zgartirmaydi.
  • strict — boshidan yoki bayroqma-bayroq; @ts-expect-error + izoh (xato yo'qolsa — TS2578), @ts-ignore va any — yo'q.
  • vazifalar — 12 qadam, har birida testlar yashil; oxirida allowJs o'chdi, sw.js — asosli istisno.

Keyingi dars: TS xato xabarlarini o'qish va tuzatish — 15-qism davomida yig'ilgan xato daftarini jamlaymiz: eng ko'p uchraydigan kodlar va uzun xabarni pastdan yuqoriga o'qish usuli.

Manbalar

  • TypeScript Handbook: "Migrating from JavaScript", "JS Projects Utilizing TypeScript", "JSDoc Reference" — typescriptlang.org/docs/handbook
  • TypeScript 3.9 Release Notes: "// @ts-expect-error Comments"
  • typescript-eslint: "Getting Started", ban-ts-comment, no-inferrable-types, shared configs — typescript-eslint.io
  • Airbnb: "ts-migrate" — github.com/airbnb/ts-migrate
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript'dan TypeScript'ga ko'chish: allowJs, checkJs va fayl-fayl o'tish — IlmHamroh