IlmHamroh
JavaScript Full-stack/18-qism. React chuqur38/42-dars19 daqiqa
Mundarija (31)

Kutubxona turlari va module augmentation: @types, declare module va "register" naqshi

Qisqacha: Kutubxona turlari uch joydan keladi: paketning o'zidan ("types" maydoni), DefinitelyTyped'dagi @types/… paketidan yoki loyihangizdagi .d.ts faylidan. Tur yetarli bo'lmasa, uni kutubxona kodiga tegmasdan kengaytirish mumkin. Bu — module augmentation: declare module "react" { interface CSSProperties { … } }. U interfeyslarning bir-biriga qo'shilishiga (declaration merging) tayanadi. Zamonaviy kutubxonalar (TanStack Router, i18next) shu yo'l bilan "register" qilinadi. Siz o'z router'ingiz yoki tarjima kalitlaringizni bir marta e'lon qilasiz, butun loyiha ularni biladi.

Bu darsda

  • Tur qayerdan kelishini (paket, @types, .d.ts) aniqlaysiz va TS7016 xatosini tuzatasiz.
  • Declaration merging va declare module bilan kutubxona turini kengaytirasiz.
  • vite-env.d.ts va ImportMetaEnv qanday ishlashini tushuntira olasiz.
  • "Register" naqshini o'zingiz yasab ko'rasiz — i18next va TanStack Router uni qanday ishlatishini tushunasiz.
  • vazifalar da style dagi CSS o'zgaruvchilari uchun React turini kengaytirasiz va TS qadamini commit qilasiz.

Oldin bilishingiz kerak: React + TS IV, Declaration fayllari, Kengaytirish va declaration merging, tsconfig Vite + React loyihada.

1. Nega bu kerak?

vazifalar dagi batafsil statistikada har teg yonida "bajarilgan ulush" chizig'i kerak bo'ldi: 2 tadan 1 tasi bajarilgan — chiziqning yarmi yashil. Chiziq uzunligi har qatorda boshqa, demak qiymat JS'dan keladi. Eng toza yo'l — CSS o'zgaruvchisi (Custom properties):

tsx
<span className="ulush" style={{ "--ulush": "50%" }} />

Brauzerda bu ishlaydi. tsc esa rozi emas:

text
TS2353: Object literal may only specify known properties, and '"--ulush"' does not exist in type 'Properties<string | number, string & {}>'.

"Obyekt literalida faqat ma'lum xususiyatlar bo'lishi mumkin, --ulush esa Properties turida yo'q." React'ning style turi faqat color, width kabi standart CSS xususiyatlarini biladi. CSS o'zgaruvchilari — -- bilan boshlanadigan istalgan nom, ularni oldindan sanab bo'lmaydi.

Nima qilamiz? as any — tekshiruvni o'chiradi. @types/react faylini node_modules da tahrirlash — keyingi npm install da o'chib ketadi.

Hayotiy o'xshatish: oshxonaga kelgan tayyor menyu kitobi. Uni chop etgan bosmaxonaga borib qayta chop ettira olmaysiz. Lekin kitobning oxiriga qo'shimcha varaq yopishtira olasiz: "Bahor maxsus taomlari". Kitob o'sha, ro'yxat kengaydi. Module augmentation — aynan shu qo'shimcha varaq.

2. Turlar qayerdan keladi

2.1 Uch manba

import { useState } from "react" yozganingizda tsc useState turini qidiradi. Qidiruv tartibi diagrammada:

flowchart TD
  I["import … from 'react'"] --> P{"paketda types bormi?"}
  P -- "ha" --> T["paket.json: types → index.d.ts"]
  P -- "yo'q" --> D{"@types/react bormi?"}
  D -- "ha" --> DT["DefinitelyTyped turlari"]
  D -- "yo'q" --> L{"loyihada declare module bormi?"}
  L -- "ha" --> M["o'z .d.ts faylingiz"]
  L -- "yo'q" --> E["TS7016: tur topilmadi"]
  • Paketning o'zida. Ko'p zamonaviy paketlar TypeScript'da yozilgan va turlarini o'zi olib keladi: package.json da "types" (yoki "exports" ichida "types") maydoni (kirish nuqtalari). Zod, Vite, TanStack Query — shunday.
  • @types/… paketi. React o'zi JavaScript'da yozilgan va tur olib kelmaydi. Uning turlari — alohida, jamoa yuritadigan DefinitelyTyped omboridagi @types/react paketida. vazifalar dagi devDependencies: "@types/react": "19.3.0", "@types/react-dom": "19.3.0".
  • Loyihangizdagi .d.ts. Hech qayerda tur yo'q bo'lsa — o'zingiz yozasiz.

2.2 @types versiyasi

@types/react versiyasi react versiyasiga mos bo'lishi kerak: kamida asosiy va kichik raqam (19.3). Nega? Turlar — API tavsifi. <Activity> React 19.2 da barqaror eksportga aylandi (Activity). @types/react 19.0 bo'lsa, import { Activity } from "react" — tur xatosi, garchi kod ishlasa ham. Teskarisi ham bor: turlarda bor, kutubxonada yo'q funksiya — ish vaqtida undefined.

@types — har doim devDependencies da (bog'liqlik turlari): turlar build'da o'chadi, brauzerga bormaydi. vazifalar da ham shunday.

2.3 TS7016: turi yo'q paket

Kichik, turlarsiz paketni o'rnatdingiz deylik — confetti-uz (o'ylab topilgan nom; main: index.js, types yo'q, @types ham yo'q):

ts
import confetti from "confetti-uz";
confetti();

tsc 7.0.2 ning haqiqiy xabari (yo'l qisqartirildi):

text
TS7016: Could not find a declaration file for module 'confetti-uz'. '…/node_modules/confetti-uz/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/confetti-uz` if it exists or add a new declaration (.d.ts) file containing `declare module 'confetti-uz';`

"confetti-uz uchun e'lon fayli topilmadi, u yashirincha any." Xabarning o'zi ikki yo'l taklif qiladi:

  1. @types/confetti-uz bormi — tekshiring (npmjs.com da qidiring).
  2. Bo'lmasa — o'z .d.ts faylingiz. Eng qisqasi declare module "confetti-uz"; — butun paket any. Yaxshisi — ishlatadigan qismingizni tavsiflash:
ts
// src/turlar/confetti-uz.d.ts
declare module "confetti-uz" {
  export default function confetti(sozlama?: { soni?: number }): void;
}

Endi confetti({ soni: 50 }) — to'g'ri, confetti({ son: 50 }) — xato. Bu shablon bilan tsc xatosiz o'tishini tekshirdik. .d.ts — faqat tur, unda kod yo'q (Declaration fayllari).

Tekshirib ko'ring: @types/react ni dependencies ga (devDependencies emas) qo'ysangiz, foydalanuvchi brauzeriga nima ortiqcha yuklanadi?

Javob

Hech narsa. Bundler faqat import qilingan kodni to'playdi, .d.ts fayllarda esa kod yo'q. Farq boshqa joyda: npm install --omit=dev (masalan, server yoki Docker'da) @types ni ham o'rnatadi — ortiqcha megabaytlar, xavfsizlik ko'rigida ortiqcha paket. Qoida bo'yicha turlar — devDependencies.

3. Declaration merging

3.1 Bir nomli ikki interfeys

Augmentation'ning poydevori — TypeScript'ning bitta xususiyati. Bir xil nomli ikki interface — bitta interfeysga qo'shiladi (Kengaytirish va declaration merging):

ts
interface Dish {
  name: string;
}

interface Dish {
  price: number;
}

const osh: Dish = { name: "Osh", price: 35000 };
console.log(osh); // { name: 'Osh', price: 35000 }

Dish endi ikkala xususiyatni ham talab qiladi. type bilan bunday qilib bo'lmaydi — Duplicate identifier 'Dish'. Shuning uchun kutubxonalar kengaytirilishi kerak bo'lgan turlarni interface qilib yozadi. React ham: interface CSSProperties, interface HTMLAttributes.

3.2 Global turlarni kengaytirish

Brauzerning global turlari (Window, Document) ham interfeys. Ularga ham "varaq qo'shish" mumkin:

ts
declare global {
  interface Window {
    bahorVersiya: string;
  }
}

console.log(window.bahorVersiya.toUpperCase());
console.log(window.bahorVersiyaa);
export {};

Xato:

text
TS2551: Property 'bahorVersiyaa' does not exist on type 'Window & typeof globalThis'. Did you mean 'bahorVersiya'?

Birinchi qator xatosiz — bahorVersiya endi Window da bor. Ikkinchisida harf adashgan — tsc to'g'ri nomni taklif qildi. declare global { … } — "modul ichidan global turni kengaytirish". Pastdagi export {}; faylni modul qiladi: declare global faqat modul faylda ishlaydi.

vazifalar da shunday fayl bor — src/trusted-types.d.ts. U yerda modul emas, skript .d.ts bo'lgani uchun declare global siz yozilgan (kanondan, qisqartirilgan):

ts
// Declaration merging: lib.dom dagi interfeysga yangi overload
// qo'shiladi — register() siyosatdan o'tgan manzilni ham qabul qiladi
interface ServiceWorkerContainer {
  register(
    manzil: string | URL | TrustedScriptURL,
    sozlama?: RegistrationOptions,
  ): Promise<ServiceWorkerRegistration>;
}

Brauzer navigator.serviceWorker.register ga Trusted Types obyektini ham qabul qiladi, lekin TypeScript'ning lib.dom i buni bilmaydi. Kanon bitta qo'shimcha "overload" yozdi — Web Worker darsidagi Trusted Types siyosati shu tufayli tsc'dan o'tdi.

Diqqat: Global turni kengaytirish — haqiqiy qiymat yaratmaydi. window.bahorVersiya turda bor, lekin uni kimdir haqiqatan yozmasa, ish vaqtida undefined. Augmentation — va'da: "bu narsa bor". Va'dani bajarish — sizning ishingiz.

4. declare module: kutubxona turini kengaytirish

4.1 React'ning CSSProperties i

Endi «Nega bu kerak?» bo'limidagi muammoga qaytamiz. @types/react da style turi — CSSProperties interfeysi. Unga yangi a'zo qo'shamiz — -- bilan boshlanadigan istalgan kalit. Buning uchun template literal tur kerak: `--${string}`:

tsx
import { useEffect, useRef } from "react";

declare module "react" {
  interface CSSProperties {
    [ozgaruvchi: `--${string}`]: string | number | undefined;
  }
}

export default function App() {
  const ref = useRef<HTMLSpanElement>(null);
  useEffect(() => {
    const qiymat = ref.current?.style.getPropertyValue("--ulush");
    console.log("--ulush =", qiymat);
  }, []);
  return (
    <p>
      #bozor{" "}
      <span ref={ref} className="ulush" style={{ "--ulush": "50%" }}>
        1/2
      </span>
    </p>
  );
}

Konsolda:

text
--ulush = 50%

Ekranda:

text
#bozor 1/2

O'qib chiqamiz:

  • declare module "react" { … } — "react moduli turlariga qo'shimcha". Kod emas, faqat tur. Build'da yo'qoladi.
  • interface CSSProperties — @types/react dagi o'sha nom. Declaration merging uni asl interfeys bilan birlashtiradi.
  • [ozgaruvchi: `--${string}`] — index signature (Index signature): "-- bilan boshlanadigan har qanday kalit". --ulush, --rang — ruxsat. -ulush yoki ulush — yo'q, ular uchun eski tekshiruv ishlaydi.
  • Konsoldagi 50% — React qiymatni elementga haqiqatan yozdi. CSS o'zgaruvchilarini React style.setProperty bilan beradi.

Muhim: modul faylda declare module "react" — kengaytirish. Agar fayl modul bo'lmasa (import/export yo'q), xuddi shu yozuv react ning butun turini almashtirib yuborardi — boshqa hech narsa qolmasdi. Shuning uchun augmentation faylida doim kamida bitta import bo'ladi.

4.2 Augmentation butun loyihaga ta'sir qiladi

Kengaytirish yozilgan faylda emas, loyihada amal qiladi: tsc hamma fayllarni bitta dastur sifatida ko'radi. react-kengaytma.d.ts ga bir marta yozdingiz — App.tsx, BatafsilStatistika.tsx va har qanday boshqa fayl "--…" ni biladi.

Teskarisi ham rost: kengaytirish loyiha tekshiruviga kirmasa, u yo'q. Augmentation'siz holat — o'sha xato:

tsx
// @ts-options: {"noUnusedLocals": false}
export default function App() {
  return <span style={{ "--ulush": "50%" }}>1/2</span>;
}

Xato:

text
TS2353: Object literal may only specify known properties, and '"--ulush"' does not exist in type 'Properties<string | number, string & {}>'.

// @ts-options qatori bu yerda faqat texnik sabab bilan: shu darsning tekshiruvchisi tsx bloklarini bitta loyiha qilib tekshiradi. Usiz yuqoridagi declare module bu blokka ham ta'sir qilib, xatoni "yashirardi". Bu — aynan shu bo'limning gapi, jonli ko'rinishda. «Vazifalar qadami» bo'limida xuddi shu tuzoq kanonda ham chiqdi.

4.3 Qayerga yozish

Kengaytirish — alohida .d.ts faylda. Bitta qoida — bitta fayl, nomi nima kengayishini aytsin: src/react-kengaytma.d.ts, src/turlar/i18next.d.ts. Komponent ichida yozish (yuqoridagi demo kabi) ishlaydi, lekin keyin uni hech kim topolmaydi.

5. vite-env.d.ts va env turlari

Vite III: env o'zgaruvchilar darsida import.meta.env.VITE_API_URL ga tur bergan edik. Endi bu fayl qanday ishlashini to'liq tushunamiz. vazifalar dagi src/vite-env.d.ts (kanondan aynan):

ts
// import.meta.env turlari (16/#28): vite/client — MODE, DEV, PROD,
// BASE_URL; o'zimizniki — pastda (.env.production, .env.development)
/// <reference types="vite/client" />

// interface — Vite'ning ImportMetaEnv'i bilan birlashishi uchun
// (declaration merging, 15/T-16; type bilan bo'lmaydi)
interface ImportMetaEnv {
  readonly VITE_API_URL: string;
}

Ikki qism:

  • /// <reference types="vite/client" /> — "Vite'ning brauzer turlarini qo'sh": import.meta.env.MODE, import.meta.hot, import x from "./rasm.png" kabi importlar turi.
  • interface ImportMetaEnv — Vite ichida ham shu nomli interfeys bor. Declaration merging ularni qo'shadi. readonly — env build paytida qotadi, kod uni o'zgartirmaydi.

Bu fayl modul emas (import yo'q) — shuning uchun declare global kerak emas, interfeys o'zi global. CSS kengaytmasi esa import "react" bilan modul — chunki u modul turini kengaytiradi, global turni emas.

Backend'da xuddi shu g'oya process.env uchun bor: declare global { namespace NodeJS { interface ProcessEnv { DATABASE_URL: string } } }. Uni Node.js qismida ishlatamiz (Muhit o'zgaruvchilari).

6. "Register" naqshi

6.1 Muammo: kutubxona sizning ma'lumotingizni bilmaydi

Tarjima kutubxonasi t("salom") funksiyasini beradi. Kutubxona yozilganda sizning kalitlaringiz ma'lum emas edi, shuning uchun t istalgan satrni qabul qiladi. t("salomm") — harf adashgan, tsc jim, ekranda esa xom kalit chiqadi.

Zamonaviy kutubxonalar buni shunday hal qiladi: kutubxona bo'sh interfeys e'lon qiladi, siz uni augmentation bilan to'ldirasiz. Kutubxona turlari shu interfeysdan o'qiydi. Naqshni o'zimiz yasab ko'ramiz — uch faylda.

6.2 O'z kichik kutubxonamiz

Birinchi fayl — "kutubxona". Register — bo'sh interfeys, Kalit esa undan tur chiqaradi (Conditional types, infer):

ts
// fayl: tarjima.ts — kichik "kutubxona"
export interface Register {}

type Kalit = Register extends { kalitlar: infer K extends string }
  ? K
  : string;

const lugat: Record<string, string> = {
  salom: "Xush kelibsiz!",
  menyu: "Bugungi menyu",
};

export function t(kalit: Kalit): string {
  return lugat[kalit] ?? kalit;
}

Register bo'sh — kalitlar yo'q, shuning uchun Kalit = string. Ilova hali ro'yxatdan o'tmagan:

ts
// fayl: ilova.ts — kalitlar ro'yxatdan o'tmagan
import { t } from "./tarjima.ts";
console.log(t("salom"));
console.log(t("salomm"));

Konsolda:

text
Xush kelibsiz!
salomm

tsc jim, ekranda xom salomm. Endi ikkinchi fayl — "register":

ts
// fayl: kalitlar.d.ts — kutubxonani "register" qilish
import "./tarjima.ts";

declare module "./tarjima.ts" {
  interface Register {
    kalitlar: "salom" | "menyu";
  }
}

O'sha ilova.ts — o'zgarishsiz:

ts
// fayl: ilova.ts — endi kalitlar tekshiriladi
import { t } from "./tarjima.ts";
console.log(t("salom"));
console.log(t("salomm"));

Xato:

text
TS2345: Argument of type '"salomm"' is not assignable to parameter of type '"menyu" | "salom"'.

Kutubxona kodi o'zgarmadi, ilova kodi ham. Faqat bitta .d.ts qo'shildi — va t ning parametri string dan "menyu" | "salom" ga torayib qoldi. Muharrir endi kalitlarni avtomatik taklif ham qiladi.

6.3 Haqiqiy kutubxonalarda

i18next (react-i18next bilan, i18n I) — CustomTypeOptions interfeysi:

ts
// src/turlar/i18next.d.ts
import "i18next";
import type uz from "../tarjimalar/uz.json";

declare module "i18next" {
  interface CustomTypeOptions {
    defaultNS: "translation";
    resources: { translation: typeof uz };
  }
}

Kalitlar to'g'ridan-to'g'ri uz.json dan olinadi: faylga yangi kalit qo'shsangiz — tur ham yangilanadi. t("menyu.sarlavha") — tekshiriladi (i18n II: type-safe kalitlar).

TanStack Router (TanStack Router) — Register interfeysi, nomi ham bizdagidek:

ts
import { createRouter } from "@tanstack/react-router";
import { routeTree } from "./routeTree.gen";

const router = createRouter({ routeTree });

declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

Shundan keyin <Link to="/menyu/$id"> dagi yo'l, params va qidiruv parametrlari — butun ilova bo'ylab tekshiriladi. Mavjud bo'lmagan sahifaga havola — tsc xatosi. Ikkala kutubxona ham hozir o'rnatilmagan — ularni 19 va 21-qismlarda o'rnatamiz. G'oyasi esa bugungi tarjima.ts bilan bir xil.

Tekshirib ko'ring: Nega kutubxona Register ni type Register = {} emas, interface Register {} qilib e'lon qiladi?

Javob

declare module ichidagi interface Register { … } asl e'lon bilan birlashishi kerak (declaration merging). type birlashmaydi: ikkinchi type Register — "Duplicate identifier" xatosi. Kengaytirilishi kerak bo'lgan har tur — interface. Kutubxona muallifi foydalanuvchiga "bu yerga varaq qo'shsa bo'ladi" degan eshikni shu bilan qoldiradi.

7. Vazifalar qadami: react-kengaytma.d.ts va commit

7.1 Teg ulushi chizig'i

refactor/turlar ning beshinchi, oxirgi bo'lagi. Yangi fayl src/react-kengaytma.d.ts (kanondan aynan):

ts
// react-kengaytma.d.ts — kutubxona turini kengaytirish (module
// augmentation, 18/#38). React'ning style prop'i (CSSProperties) faqat
// ma'lum CSS xossalarini biladi: style={{ "--ulush": "40%" }} — tsc
// xatosi (o'lchandi, natijalar/38-*). CSS o'zgaruvchilari (custom
// properties) — "--" bilan boshlanadigan har qanday nom; React ularni
// style.setProperty bilan yozadi (CSSOM — CSP style-src'ga tegmaydi).
// "declare module" — @types/react dagi interfeysga yangi a'zo qo'shadi
// (declaration merging), faylning o'zi kod emas
import "react";

declare module "react" {
  interface CSSProperties {
    [ozgaruvchi: `--${string}`]: string | number | undefined;
  }
}

Izohdagi bir gapga e'tibor bering: "CSSOM — CSP style-src ga tegmaydi". vazifalar da CSP style-src 'self' — ichki style="…" atributlari taqiqlangan. React esa style prop'ini atribut sifatida emas, element.style.setProperty(…) bilan yozadi. Bu yo'l CSP'ga tushmaydi (CSP). Shuning uchun CSS o'zgaruvchisi vazifalar da xavfsiz.

BatafsilStatistika.tsx dagi ishlatilishi — teg jadvalidagi «bajarildi» katakchasida:

tsx
<span
  className="ulush"
  aria-hidden="true"
  style={{
    "--ulush": `${Math.round((t.bajarildi / t.jami) * 100)}%`,
  }}
/>

aria-hidden="true" — chiziq bezak, raqam yonida turibdi. Malika raqamni eshitadi, chiziqni emas (React'da accessibility asoslari). CSS'da chiziq gradient bilan chiziladi:

css
#batafsil .ulush {
  display: block;
  height: var(--joy-1);
  margin-top: var(--joy-1);
  border-radius: var(--joy-1);
  background: linear-gradient(
    to right,
    var(--rang-asosiy) var(--ulush, 0%),
    var(--rang-chegara) var(--ulush, 0%)
  );
}

var(--ulush, 0%) — o'zgaruvchi berilmasa, 0%.

7.2 Tuzoq: test loyihasi .d.ts ni ko'rmadi

Kanonda birinchi npm run tip (tsc -b) yiqildi — xuddi «Nega bu kerak?» bo'limidagi TS2353. Lekin tsc -p tsconfig.app.json — 0 xato. Farq qayerda?

vazifalar da uchta tsconfig loyihasi bor (tsconfig Vite + React loyihada): app, node va test. Testlar src/ dagi komponentlarni import qiladi, demak BatafsilStatistika.tsx test loyihasida ham tekshiriladi. Test loyihasining include ro'yxatida esa global .d.ts fayllar aniq sanalgan edi — yangisi yo'q. «Augmentation butun loyihaga ta'sir qiladi» bo'limidagi qoida aynan shu: kengaytma test loyihasiga kirmadi — u yerda yo'q edi. Tuzatish (kanondan):

json
  // .d.ts — global e'lonlar (import.meta.env, trustedTypes, React style'da
  // CSS o'zgaruvchilari — 18/#38): testlar
  // import qilgan src/ fayllari ularga tayanadi (17/#28)
  "include": [
    "tekshiruv/**/*.ts",
    "tekshiruv/**/*.tsx",
    "src/vite-env.d.ts",
    "src/trusted-types.d.ts",
    "src/react-kengaytma.d.ts"
  ]

Kanonda bir haqiqat ham yozib qo'yildi: avval bu "TS 7 va TS 6 farqi" deb gumon qilingan edi. Tekshirilganda -p tsconfig.app.json ikkala versiyada ham 0 xato berdi — farq versiyada emas, loyihada edi. Xato sababini taxmin bilan emas, o'lchab topish — shu.

7.3 Commit

Besh darsdagi ish — bitta commit:

bash
git add -A
git commit

Commit (kanon): refactor: tsconfig qo'shimcha bayroqlar, Tugma nomi — union, CSSProperties kengaytmasi. Tarkibi:

  • tsconfig.app.json — uch bayroq (34-dars), tsconfig.test.json — include ga yangi .d.ts.
  • ui/Tugma.tsx — Nomi union'i (37-dars).
  • src/react-kengaytma.d.ts, BatafsilStatistika.tsx, vazifalar.css — teg ulushi chizig'i.

Tekshiruvlar (haqiqiy, natijalar/tekshiruv-38.txt):

  • npm test — node:test ℹ pass 170, Vitest Tests 45 passed (45). lint, format:check, tip, knip — exit 0.
  • Build: dist/assets/index-Cn0-5Xqi.js 257.56 kB │ gzip: 81.84 kB. Turlar build'da yo'qoladi — o'zgarish faqat yangi CSS qoidasi va <span>.
  • Brauzer tekshiruvi — 159/159, e2e-18 — 50/50.
  • Diff: 6 fayl, +68 −8.

Hash sizda boshqacha chiqadi — u fayl tarkibidan hisoblanadi.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
TS7016: Could not find a declaration file paketda tur yo'q @types/… yoki declare module
import { Activity } — tur xatosi, kod ishlaydi @types/react eski @types versiyasini react ga moslang
TS2353 … '"--ulush"' does not exist CSSProperties kengaytirilmagan react-kengaytma.d.ts
butun react turi yo'qoldi declare module "react" modul bo'lmagan faylda faylga import "react"
tsc -p app — 0, tsc -b — xato .d.ts test loyihasi include ida yo'q include ga qo'shing
Duplicate identifier type ni birlashtirishga urinish interface
window.x turda bor, ishda undefined augmentation qiymat yaratmaydi qiymatni haqiqatan yozing

9. Mashqlar

Mashqlar kurs/mashqlar/18/38-kutubxona-turlari/ da.

1-mashq (oson): tur qayerdan?

Har paket uchun turlar qayerdan keladi: paketning o'zi, @types yoki o'z .d.ts?

  • react —
  • zod (TypeScript'da yozilgan, "types" maydoni bor) —
  • confetti-uz (turlarsiz, @types ham yo'q) —
Yechim
  • @types — React JavaScript'da yozilgan, turlari DefinitelyTyped'da (@types/react).
  • paketning o'zi — package.json dagi "types" tsc'ni .d.ts ga yo'naltiradi, alohida paket kerak emas.
  • o'z .d.ts — declare module "confetti-uz" bilan, ishlatadigan qismingizni tavsiflab.

2-mashq (o'rta): data-* emas, CSS o'zgaruvchisi

Taomlar reytingi: har taom yonida --yulduz CSS o'zgaruvchisi ("80%" kabi). Komponent Rating({ name, percent }) — <p> ichida nom va <span style={{ "--yulduz": … }}>. Effekt bilan birinchi <span> ning --yulduz qiymatini konsolga chiqaring. Ishora: «React'ning CSSProperties i» bo'limidagi kengaytma.

Yechim
tsx
// @ts-options: {"noUnusedParameters": false}
import { useEffect, useRef } from "react";

declare module "react" {
  interface CSSProperties {
    [ozgaruvchi: `--${string}`]: string | number | undefined;
  }
}

type RatingProps = { name: string; percent: number };

function Rating({ name, percent }: RatingProps) {
  const style = { "--yulduz": `${percent}%` };
  return (
    <p>
      {name} <span className="yulduz" style={style} />
    </p>
  );
}

export default function App() {
  const ref = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const span = ref.current?.querySelector("span");
    console.log(span?.style.getPropertyValue("--yulduz"));
  }, []);
  return (
    <div ref={ref}>
      <Rating name="Osh" percent={80} />
      <Rating name="Manti" percent={60} />
    </div>
  );
}

Konsolda:

text
80%

Ekranda:

text
Osh
Manti

Birinchi qatordagi @ts-options — faqat shu dars tekshiruvchisi uchun («Augmentation butun loyihaga ta'sir qiladi» bo'limidagi sabab), o'z loyihangizda kerak emas. Kengaytma bo'lmasa — xato, lekin boshqa raqam bilan: TS2559: Type '{ "--yulduz": string; }' has no properties in common with type 'Properties<…>'. Obyekt alohida o'zgaruvchida bo'lgani uchun tsc "ortiqcha xususiyat" (TS2353) emas, "umumiy xususiyat yo'q" deydi — ma'nosi bir xil. --yulduz ni CSS'da width: var(--yulduz) yoki gradient bilan ishlatasiz. Haqiqiy loyihada kengaytma komponent faylida emas, react-kengaytma.d.ts da bo'ladi.

3-mashq (qiyin): o'z "register" ingiz

«O'z kichik kutubxonamiz» bo'limidagi naqsh bilan buyurtma.ts kutubxonasini yozing: export interface Register {} va holatMatni(holat) funksiyasi. Register da holatlar berilsa — holat faqat shu satrlar, aks holda string. Keyin holatlar.d.ts da "qabul" | "tayyor" | "yetkazildi" ni ro'yxatdan o'tkazing va holatMatni("tayyorr") xato berishini tekshiring. Ishora: Register extends { holatlar: infer H extends string } ? H : string.

Yechim
ts
// buyurtma.ts
export interface Register {}

type Holat = Register extends { holatlar: infer H extends string }
  ? H
  : string;

export function holatMatni(holat: Holat): string {
  return `Buyurtma holati: ${holat}`;
}
ts
// holatlar.d.ts
import "./buyurtma.ts";

declare module "./buyurtma.ts" {
  interface Register {
    holatlar: "qabul" | "tayyor" | "yetkazildi";
  }
}
ts
// ilova.ts
import { holatMatni } from "./buyurtma.ts";
console.log(holatMatni("tayyor")); // Buyurtma holati: tayyor
holatMatni("tayyorr");
// ❌ TS2345: … '"qabul" | "tayyor" | "yetkazildi"'

holatlar.d.ts siz Holat — string, ikkala chaqiruv ham o'tadi. U bilan — faqat uchta satr. Uch faylning hammasi tsc'ning bitta loyihasida bo'lishi shart (include) — «Tuzoq: test loyihasi .d.ts ni ko'rmadi» bo'limidagi saboq. Yechim uch faylli loyiha sifatida tsc 7.0.2 bilan tekshirilgan.

4-mashq: Vazifalar qadami

react-kengaytma.d.ts ni qo'shing, BatafsilStatistika ga ulush chizig'ini yozing. Avval kengaytmasiz npm run tip ni ishga tushiring — TS2353 ni ko'ring. Keyin kengaytma bilan — va tsconfig.test.json dagi include ni unutib ko'ring: qaysi buyruq yiqiladi? Hammasini to'g'rilab, commit qiling.

Yechim
  • Kengaytmasiz: tsc — BatafsilStatistika.tsx(…): error TS2353: … '"--ulush"' does not exist in type 'Properties<…>'.
  • Kengaytma bor, include da yo'q: tsc -p tsconfig.app.json — 0 xato, npm run tip (tsc -b) — o'sha TS2353, test loyihasidan.
  • Ikkalasi to'g'ri: npm run check — toza (node 170, Vitest 45). npm run build, npm run preview — statistika panelida teg qatorlari ostida chiziq.
  • Commit — refactor: tsconfig qo'shimcha bayroqlar, Tugma nomi — union, CSSProperties kengaytmasi. PR'ni birlashtiring.

10. Real ishda

  • @types versiyasini kuzatish — Dependabot/Renovate react va @types/react ni birga yangilashi uchun guruh qoidasi yoziladi (Bog'liqliklarni yangilash).
  • Augmentation fayllari — har jiddiy loyihada: env.d.ts, i18next.d.ts, router.d.ts, styled.d.ts (styled-components'ning DefaultTheme i ham shunday kengaytiriladi).
  • "Register" naqshi — TanStack Router, TanStack Query (Register — xato turi uchun), i18next, Auth.js (Session turi). Kutubxona hujjatida "TypeScript" bo'limi deyarli doim shu haqida.
  • Intervyu savollari: "declaration merging nima?", "type va interface qachon farq qiladi?" (javob: augmentation), "kutubxonada tur yo'q bo'lsa nima qilasiz?".

Xulosa

  • Turlar: paketning o'zidan ("types"), @types/… (DefinitelyTyped) yoki o'z .d.ts dan; topilmasa — TS7016.
  • @types — devDependencies da, versiyasi kutubxonaga mos.
  • Declaration merging — bir nomli interface lar qo'shiladi; type — yo'q.
  • declare module "react" { interface CSSProperties { … } } — kutubxona turini kengaytirish; fayl modul bo'lsin (import "react"), loyiha tekshiruviga kirsin.
  • "Register" naqshi: kutubxona bo'sh interfeys beradi, siz to'ldirasiz — i18next, TanStack Router.
  • vazifalar: react-kengaytma.d.ts (--ulush), test loyihasi include tuzog'i, commit — node 170, Vitest 45, brauzer 159/159.

Keyingi dars: React'da accessibility asoslari — semantik teglar, label, aria atributlari va avtomatik tekshiruv.

Manbalar

  • TypeScript: Declaration Merging — Module Augmentation, Global augmentation — typescriptlang.org/docs/handbook/declaration-merging.html
  • DefinitelyTyped — github.com/DefinitelyTyped/DefinitelyTyped
  • Vite: "Env Variables and Modes — IntelliSense for TypeScript" — vite.dev/guide/env-and-mode
  • i18next: TypeScript — i18next.com/overview/typescript
  • TanStack Router: Type Safety — "Register" — tanstack.com/router/latest/docs/framework/react/guide/type-safety
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Kutubxona turlari va module augmentation: @types, declare module va "register" naqshi — IlmHamroh