WisarWisar
Dasturlash kitobi/11-QISM — React44 daqiqa

11.14-bob: TypeScript bilan React

11-QISM — Frontend: React · 14-mavzu


1. Kirish va motivatsiya

7-QISM'da TypeScript'ni o'rgandik — turlar, interface, generics, utility types. Endi uni React bilan birlashtiramiz, va bu birikma — zamonaviy professional React loyihasining standarti. 2026-yilda deyarli barcha jiddiy React loyiha TypeScript'da yoziladi (oddiy JavaScript emas), va buning sabablari aniq: xato compile paytida tutiladi (foydalanuvchi ko'rishidan oldin), autocomplete (muharrir har props/funksiyani taklif qiladi), va refactoring xavfsiz bo'ladi (nomni o'zgartirsangiz, ishlatilgan hamma joy avtomatik topiladi). Proplarni noto'g'ri uzatish, mavjud bo'lmagan maydonga murojaat, funksiyaga noto'g'ri argument — bularning hammasini TypeScript kod yozayotgan paytingizda tutadi.

Lekin React + TypeScript o'z nozikliklariga ega: props turlarini qanday yozish (interface yoki type?), childrenning turi nima, useState/useRef/useReducer turlarini qanday belgilash, hodisa (event) turlari, generic komponentlar, va eng ko'p munozara qiladigan React.FC — ishlatish kerakmi yoki yo'qmi. Bu bobda aynan shu amaliy nozikliklarni o'rganamiz. 11.10-bobda Zod + TypeScript birikmasini (forma) ko'rganmiz — endi uni butun React kontekstiga kengaytiramiz: type-safe komponent, hook, API qatlami.

Bu bob: nega TS React'da (xato compile'da, autocomplete, refactoring), setup (.tsx, react-ts, @types), komponent va props turlari (interface/type, optional, default), children turi (ReactNode), hooklar turlari (useState<T>, useRef, useReducer), event turlari (onChange/onClick/onSubmit), generic komponentlar (List<T>), custom hook turlari, React.FC munozarasi (nega ko'pincha ishlatilmaydi), utility types React'da (Omit/Pick/Partial — props), Context turlari, va Zod + TS birikmasi (type-safe API). Har mavzu to'liq, amaliy va zamonaviy holatda, izohli kod bilan ochib beriladi.

O'xshatish: TypeScript React'da — bu qurilishdagi texnik chizma va o'lcham nazorati. JavaScript bilan React yozish — bu chizmasiz bino qurish: ishlayveradi, lekin bir devorni noto'g'ri o'lchab qo'ysangiz (props'ni noto'g'ri uzatsangiz), buni faqat bino qulaganda (foydalanuvchi xato ko'rganda) bilasiz. TypeScript — bu aniq chizma + o'lcham tekshirgich: har bir g'isht (komponent) qanday ulanishini (qaysi props, qaysi turda) oldindan belgilaysiz, va agar noto'g'ri ulasangiz — chizma darrov qizil chiroq beradi (muharrirda xato — kod yozayotgan paytingizda, bino qurilmasdan oldin). Bundan tashqari, chizma sizga avtomat yordamchi beradi (autocomplete — "bu yerga shu g'isht mos keladi"), va bino tuzilishini o'zgartirganda (refactoring) — chizma barcha bog'liq joyni avtomatik yangilaydi. Tajribali quruvchi hech qachon chizmasiz qurmaydi.

Nega muhim?

  • Professional standart — 2026'da jiddiy React loyiha = TypeScript (JS emas); ish e'lonlarida talab.
  • Kam xato — props/maydon/argument xatolari compile paytida (foydalanuvchi emas) tutiladi.
  • Unumdorlik — autocomplete, refactoring, "go to definition" — kod yozish tezroq va ishonchli.
  • Komanda — turlar — "jonli hujjat" (boshqa dasturchi komponentni qanday ishlatishni darrov ko'radi).

2. Nazariya — chuqur tushuntirish

2.1. Nega TypeScript React'da

text
  JAVASCRIPT (xato ish vaqtida — foydalanuvchi ko'radi):
  <UserCard name={user.nam} />        // "nam" — xato (name kerak)  undefined  bug
  function UserCard({ name, age }) { return <h2>{nme}</h2>; }   // "nme" — xato  crash
  //  bu xatolar FAQAT ilova ishlaganda (yoki umuman) seziladi

  TYPESCRIPT (xato KOD yozayotganda — muharrirda qizil):
  interface Props { name: string; age: number; }
  <UserCard name={user.nam} />        //  muharrir DARROV: "nam mavjud emas"
  function UserCard({ name, age }: Props) { return <h2>{nme}</h2>; }  //  "nme topilmadi"

  3 ASOSIY FOYDA:
   Xato compile paytida (foydalanuvchi ko'rishidan OLDIN)
   Autocomplete (har props/metod/maydon taklif qilinadi — tez yozish)
   Refactoring xavfsiz (nom o'zgarsa — barcha ishlatish joyi topiladi)

   TS — React'da xatolarni ERTA (yozaytganda) tutadi (JS — kech, ish vaqtida)
   Turlar — "jonli hujjat" (komponentni qanday ishlatish — kodda ko'rinadi)

Nega TypeScript React'da — uchta asosiy foyda. JavaScript'da xatolar ish vaqtida (runtime) seziladi — masalan <UserCard name={user.nam} /> (xato — name kerak edi) yoki funksiyada {nme} (xato) — bular faqat ilova ishlaganda (yoki umuman sezilmasdan, jim bug bo'lib) namoyon bo'ladi. TypeScript'da esa bu xatolar kod yozayotgan paytda muharrirda qizil chiziq bilan ko'rsatiladi (compile paytida — foydalanuvchi ko'rishidan oldin). Uch asosiy foyda: (1) xato erta tutiladi (compile paytida, runtime emas); (2) autocomplete — muharrir har bir props, metod, maydonni taklif qiladi (tez va ishonchli yozish); (3) refactoring xavfsiz — nom yoki tuzilishni o'zgartirganda, barcha ishlatish joylari avtomatik topiladi (qo'lda qidirmasdan). Ikki muhim nuqta: (1) TS xatolarni erta (yozayotganda) tutadi — bu junior va senior loyihasining sifat farqini belgilaydi; (2) turlar — "jonli hujjat" (living documentation): komponentni qanday ishlatish (qaysi props, qaysi turda) kodning o'zida ko'rinadi (alohida hujjat yozish kerak emas). Aynan shu sabab TypeScript zamonaviy React standartiga aylandi.

2.2. Setup — .tsx, react-ts, @types

text
  YANGI LOYIHA (TS bilan — 11.3):
  npm create vite@latest my-app -- --template react-ts   # React + TypeScript

  FAYL KENGAYTMASI:
  .tsx — JSX'li TypeScript fayl (komponentlar)         // React komponent  .tsx
  .ts  — JSX'siz TypeScript (util, hook, types)         // oddiy mantiq  .ts

  TURLAR (@types — kutubxonalar uchun):
  - react, react-dom turlari — react-ts shablonda avtomatic
  - boshqa kutubxona: npm i -D @types/<paket>  (agar o'zi TS bermasa)

  tsconfig.json (asosiy sozlamalar — 7.1):
  "jsx": "react-jsx",          // yangi JSX transform (import React kerak emas — 11.2)
  "strict": true,              // qattiq tekshiruv (tavsiya — barcha himoya)

  ┌────────────────────────────────────────────────────────────┐
  │ Komponent  .tsx | Mantiq/util/types  .ts                 │
  │ react-ts shablon — turlar va sozlama tayyor                 │
  └────────────────────────────────────────────────────────────┘

   react-ts shablon 11.3-bob — turlar, tsconfig, sozlama tayyor (qo'lda sozlash kerak emas)
   strict: true — barcha himoyani yoq (null tekshiruv, implicit any yo'q — 7.1)

Setup — React + TypeScript loyihasini sozlash. Yangi loyiha: npm create vite@latest my-app -- --template react-ts 11.3-bob — React + TypeScript shabloni (turlar, tsconfig, sozlamalar tayyor). Fayl kengaytmalari: .tsx (JSX'li TypeScript — React komponentlari uchun), .ts (JSX'siz — util funksiyalari, custom hooklar, type ta'riflari uchun). Turlar (@types): react/react-dom turlari react-ts shablonda avtomatik o'rnatilgan; boshqa kutubxona o'z turlarini bermasa (npm i -D @types/<paket> bilan o'rnatasiz — masalan @types/node). tsconfig.json asosiy sozlamalari 7.1-bob: "jsx": "react-jsx" (yangi JSX transform — import React kerak emas — 11.2: 2.4), "strict": true (qattiq tekshiruv — tavsiya, barcha himoyani yoqadi: null tekshiruv, implicit any yo'q). Ikki nuqta: (1) react-ts shabloni 11.3-bob — turlar, tsconfig, sozlama tayyor (qo'lda sozlash kerak emas, darrov ishlaysiz); (2) strict: true — barcha TypeScript himoyasini yoqadi (eng muhim sozlama — usiz TypeScriptning foydasi yarmiga kamayadi). Setup oddiy — react-ts shabloni bilan bir buyruqda tayyor.

2.3. Komponent va props turlari — interface/type

text
  PROPS TURI — interface yoki type bilan (komponentga kiruvchi ma'lumot):

  // interface bilan (keng ishlatiladi):
  interface ButtonProps {
    text: string;
    variant: "primary" | "danger";    // union — faqat shu qiymatlar 7.4-bob
    disabled?: boolean;                // ? — ixtiyoriy
    onClick: () => void;               // funksiya turi
  }
  function Button({ text, variant, disabled, onClick }: ButtonProps) {
    return <button className={variant} disabled={disabled} onClick={onClick}>{text}</button>;
  }

  // type bilan (ekvivalent — ko'pincha union/utility uchun):
  type ButtonProps = { text: string; variant: "primary" | "danger" };

  INTERFACE vs TYPE (React props uchun):
  - interface — kengaytiriladigan (extends), object shakli uchun (an'anaviy)
  - type — union, intersection, utility types uchun (moslashuvchanroq — 7.2)
   ikkalasi ham ishlaydi; izchillik muhim (jamoa tanlovi)

   Props turi — komponentning "shartnomasi" (qanday ishlatish — autocomplete + tekshiruv)
   ? — ixtiyoriy prop; union ("a"|"b") — faqat ruxsat etilgan qiymatlar (7.4)

Komponent va props turlari — React + TypeScript'ning eng asosiy ko'nikmasi. Props turi interface yoki type bilan belgilanadi: interface ButtonProps { text: string; variant: "primary" | "danger"; disabled?: boolean; onClick: () => void } — har props nomi va turi yoziladi. Muhim elementlar: union ("primary" | "danger" — faqat shu qiymatlar ruxsat etiladi — 7.4), ? (ixtiyoriy prop — disabled?), funksiya turi (onClick: () => void). Komponentga turni qo'shasiz: function Button({ text, variant }: ButtonProps). interface vs type (React props uchun): interface — kengaytiriladigan (extends), obyekt shakli uchun an'anaviy; type — union, intersection, utility types uchun moslashuvchanroq 7.2-bob; ikkalasi ham ishlaydi, eng muhimi — izchillik (jamoa bir uslubni tanlab, unga rioya qilsin). Ikki nuqta: (1) props turi — komponentning "shartnomasi" (contract): u qanday ishlatilishini aniq belgilaydi (noto'g'ri props — darrov xato, va autocomplete props'ni taklif qiladi); (2) ? ixtiyoriy props uchun, union ruxsat etilgan qiymatlarni cheklash uchun (variant="warning" — agar union'da yo'q bo'lsa — xato). Bu — type-safe komponentning poydevori.

2.4. children turi — ReactNode

text
  CHILDREN — komponent ichidagi JSX (11.2: 2.8) — turi ReactNode:

  interface CardProps {
    title: string;
    children: React.ReactNode;        //  ReactNode — JSX, matn, raqam, array, null... (hammasi)
  }
  function Card({ title, children }: CardProps) {
    return <div className="card"><h3>{title}</h3>{children}</div>;
  }

  CHILDREN TURLARI (qaysi birini qachon):
  - React.ReactNode — eng keng (JSX, string, number, array, null — odatda SHU)
  - React.ReactElement — faqat JSX element (string/null emas — kamroq)
  - (children?: ReactNode) — ixtiyoriy children

  PropsWithChildren (yordamchi — children'ni avtomatik qo'shadi):
  function Card({ title, children }: React.PropsWithChildren<{ title: string }>) {...}

   children turi — deyarli har doim React.ReactNode (eng moslashuvchan)
   PropsWithChildren<Props> — children'ni qo'lda yozmasdan qo'shadi (qulay)

children turi — komponent ichidagi JSX'ning (11.2: 2.8) turi. Eng keng va standart tur — React.ReactNode: u JSX element, matn (string), raqam (number), array, null, undefined, boolean — ya'ni komponent ichiga qo'yish mumkin bo'lgan hamma narsani qamraydi. interface CardProps { title: string; children: React.ReactNode }. Children turlari (qaysi birini qachon): React.ReactNode (eng keng — odatda shuni ishlatasiz); React.ReactElement (faqat JSX element — string/null qabul qilmaydi — kamroq, qattiqroq); ixtiyoriy children — children?: ReactNode. PropsWithChildren (yordamchi tur) — childrenni avtomatik qo'shadi: React.PropsWithChildren<{ title: string }>title + children (qo'lda children: ReactNode yozish o'rniga). Ikki nuqta: (1) children turi deyarli har doim React.ReactNode (eng moslashuvchan — barcha bola turlarini qabul qiladi); (2) PropsWithChildren<Props>childrenni qo'lda yozmasdan qo'shadigan qulay yordamchi (o'rovchi komponentlar — Card, Layout, Modal — uchun ideal). Bu — wrapper komponentlarning standart turi.

2.5. useState turlari — inference, generic, union

text
  useState — TURNI ko'pincha O'ZI ANGLAYDI (inference), ba'zan qo'lda:

  // 1. INFERENCE (TS boshlang'ich qiymatdan turni ANGLAYDI — qo'lda kerak emas):
  const [count, setCount] = useState(0);         // number (0 dan)
  const [name, setName] = useState("");          // string
  const [open, setOpen] = useState(false);       // boolean

  // 2. GENERIC (murakkab tur — qo'lda belgila):
  const [user, setUser] = useState<User | null>(null);   // User obyekt yoki null
  const [items, setItems] = useState<Product[]>([]);     // Product massivi
  //  useState<T>(boshlang'ich) — T turni aniq beradi

  // 3. UNION (bir nechta holat):
  const [status, setStatus] = useState<"idle" | "loading" | "error">("idle");

  QACHON GENERIC kerak:
  - boshlang'ich null/bo'sh ([]) — TS turni anglay olmaydi (null/never[])
  - union turi (status — bir nechta qiymat)

   Oddiy qiymat (0, "", false) — inference yetadi (generic kerak emas)
   null/bo'sh massiv/union — generic kerak: useState<User|null>(null), useState<T[]>([])

useState turlari — ko'pincha TypeScript turni o'zi anglaydi (inference), ba'zan qo'lda belgilanadi. (1) Inference — boshlang'ich qiymatdan tur avtomatik aniqlanadi: useState(0) number, useState("") string, useState(false) boolean (qo'lda tur yozish kerak emas). (2) Generic — murakkab tur uchun qo'lda: useState<User | null>(null) (User obyekt yoki null), useState<Product[]>([]) (Product massivi) — useState<T>(boshlang'ich) bilan turni aniq berasiz. (3) Union — bir nechta holat: useState<"idle" | "loading" | "error">("idle") (status). Qachon generic kerak: (a) boshlang'ich qiymat null yoki bo'sh massiv ([]) bo'lganda — TS turni anglay olmaydi (null yoki never[] deb biladi, keyin setUser(realUser) xato beradi); (b) union turi (status). Ikki qoida: (1) oddiy qiymat (0, "", false) bilan boshlasangiz — inference yetadi (generic ortiqcha); (2) null, bo'sh massiv, yoki union bilan — generic kerak (useState<User|null>(null), useState<T[]>([])). Bu — useStateni to'g'ri turlashning amaliy qoidasi (eng ko'p ishlatiladigan hook).

2.6. useRef turlari — DOM va mutable

text
  useRef — ikki xil ishlatish (11.5: 2.12, 2.13), ikki xil tur:

  // 1. DOM REF (element turi + null — boshlang'ich):
  const inputRef = useRef<HTMLInputElement>(null);   // <input> elementi (yoki null)
  inputRef.current?.focus();                          // ?. — null bo'lishi mumkin (render'dan oldin)
  // DOM tur: HTMLInputElement, HTMLDivElement, HTMLButtonElement... (element'ga mos)

  // 2. MUTABLE QIYMAT (render'siz qiymat — 11.5: 2.13):
  const countRef = useRef<number>(0);                // number (boshlang'ich 0)
  const timerRef = useRef<number | null>(null);      // interval ID (number yoki null)
  countRef.current += 1;                              // .current — to'g'ridan o'zgartiriladi

  DOM TUR QANDAY TOPISH:
  <input>  HTMLInputElement | <div>  HTMLDivElement | <button>  HTMLButtonElement
  <form>  HTMLFormElement | <a>  HTMLAnchorElement | <canvas>  HTMLCanvasElement

   DOM ref: useRef<HTMLXElement>(null) — null boshlang'ich (DOM render'dan keyin to'ladi)
   inputRef.current?.focus() — ?. (null tekshiruv — strict mode — 2.5)

useRef turlari — ref'ning ikki ishlatilishiga (11.5: 2.12, 2.13) ikki tur. (1) DOM refuseRef<HTMLInputElement>(null) — element turi (HTMLInputElement) va boshlang'ich null (DOM render'dan keyin to'ladi). Ishlatishda inputRef.current?.focus()?. (optional chaining) kerak, chunki current null bo'lishi mumkin (render'dan oldin). DOM turlari elementga mos: <input> HTMLInputElement, <div> HTMLDivElement, <button> HTMLButtonElement, <form> HTMLFormElement, <canvas> HTMLCanvasElement, va h.k. (2) Mutable qiymat (render'siz — 11.5: 2.13) — useRef<number>(0) (number), useRef<number | null>(null) (interval ID); .currentni to'g'ridan o'zgartirasiz (countRef.current += 1). Ikki nuqta: (1) DOM ref — useRef<HTMLXElement>(null) (null boshlang'ich, element turi), va currentni ?. bilan ishlat (strict mode null tekshiruvi talab qiladi — 2.5); (2) DOM turni topish oson — element nomini katta harf bilan HTML + Element (HTMLInputElement). To'g'ri DOM tur — autocomplete'ni ham beradi (inputRef.current?. keyin barcha input metodlari taklif qilinadi).

2.7. useReducer turlari — state va action union

text
  useReducer — state turi + action turi (discriminated union — 7.4):

  interface State { count: number; loading: boolean; }

  type Action =                          //  discriminated union — har action o'z shakli
    | { type: "increment" }
    | { type: "decrement" }
    | { type: "set"; payload: number }   // payload faqat shu action'da
    | { type: "loading"; payload: boolean };

  function reducer(state: State, action: Action): State {   // turlar — type-safe
    switch (action.type) {
      case "increment": return { ...state, count: state.count + 1 };
      case "set": return { ...state, count: action.payload };   // payload — number (TS biladi)
      case "loading": return { ...state, loading: action.payload };   // payload — boolean
      default: return state;
    }
  }

  const [state, dispatch] = useReducer(reducer, { count: 0, loading: false });
  dispatch({ type: "set", payload: 5 });     //  type-safe (payload number kerak)
  dispatch({ type: "set" });                  //  xato (set payload talab qiladi)

   Action — discriminated union (type maydon ajratadi; payload har action'da har xil — 7.4)
   TS payload turini "type"dan aniqlaydi (set  number, loading  boolean) — type-safe dispatch

useReducer turlari — state va action turlarini belgilaydi (11.6 davomi). State turi oddiy interface (interface State { count: number; loading: boolean }). Action turidiscriminated union 7.4-bob: har action o'z shakliga ega, type maydon ularni ajratadi — type Action = { type: "increment" } | { type: "set"; payload: number } | { type: "loading"; payload: boolean }. Bu — TypeScript'ning eng kuchli imkoniyatlaridan biri: reducer ichida switch (action.type) qilganda, har caseda TS payload turini aniq biladi (case "set" action.payload — number; case "loading" boolean). Reducerga turlar qo'shasiz: function reducer(state: State, action: Action): State. Va dispatch ham type-safe: dispatch({ type: "set", payload: 5 }) , lekin dispatch({ type: "set" }) (payload talab qilinadi), dispatch({ type: "set", payload: "x" }) (number kerak). Ikki nuqta: (1) action — discriminated union (type maydon orqali ajratiladi, har action'ning o'z payload turi) — bu TS'ning reducer bilan eng go'zal birikmasi; (2) TS payload turini typedan avtomatik aniqlaydi (type-safe dispatch va reducer). Bu — murakkab state mantig'ini butunlay xavfsiz qiladi (noto'g'ri action — compile xatosi).

2.8. Event turlari — onChange, onClick, onSubmit

text
  HODISA (EVENT) TURLARI — handler funksiyaga to'g'ri event turi:

  // INPUT onChange:
  function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    setValue(e.target.value);            // e.target.value — string (TS biladi)
  }

  // BUTTON onClick:
  function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
    e.preventDefault();
  }

  // FORM onSubmit:
  function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
  }

  // KEYBOARD:
  function handleKey(e: React.KeyboardEvent<HTMLInputElement>) {
    if (e.key === "Enter") {...}
  }

  INLINE — TS turni O'ZI anglaydi (qo'lda kerak emas):
  <input onChange={(e) => setValue(e.target.value)} />   // e — avtomatik ChangeEvent (inference)

  ┌────────────────────────────────────────────────────────────┐
  │ ChangeEvent (input) | MouseEvent (click) | FormEvent (form) │
  │ KeyboardEvent (key) | FocusEvent (focus/blur)              │
  └────────────────────────────────────────────────────────────┘

   Inline handler — TS event turni o'zi anglaydi (alohida funksiyada qo'lda yoz)
   Event<HTMLXElement> — element turini ham beradi (e.target/currentTarget to'g'ri turda)

Event turlari — hodisa handler'lariga to'g'ri tur. Asosiy event turlari: React.ChangeEvent<HTMLInputElement> (input/select onChange — e.target.value string), React.MouseEvent<HTMLButtonElement> (onClick), React.FormEvent<HTMLFormElement> (onSubmit), React.KeyboardEvent<HTMLInputElement> (onKeyDown — e.key), React.FocusEvent (onFocus/onBlur). Har biri generic argument oladi — element turi (<HTMLInputElement>) — bu e.target/e.currentTargetni to'g'ri turda beradi. Muhim qulaylik: inline handler'larda TS turni o'zi anglaydi (inference) — <input onChange={(e) => setValue(e.target.value)} />e avtomatik ChangeEvent deb biladi (qo'lda tur yozish kerak emas). Faqat alohida funksiyada (komponentdan tashqarida yoki yuqorida e'lon qilingan) tur qo'lda yoziladi (function handleChange(e: React.ChangeEvent<HTMLInputElement>)). Ikki nuqta: (1) inline handler — TS event turni avtomatik anglaydi (eng qulay); alohida funksiya — qo'lda tur ber; (2) Event<HTMLXElement> — element turini ham beradi (autocomplete: e.target.value, e.currentTarget.disabled — to'g'ri turda). Bu — forma va interaktiv komponentlarni type-safe qiladi (e.target.valueni noto'g'ri ishlatish — compile xatosi).

2.9. Generic komponentlar — List

text
  GENERIC KOMPONENT — har qanday tur bilan ishlaydigan, lekin TYPE-SAFE komponent:

  interface ListProps<T> {                       //  T — generic tur 7.3-bob
    items: T[];
    renderItem: (item: T) => React.ReactNode;    // har element uchun UI
    keyExtractor: (item: T) => string | number;  // key (11.4: 2.13)
  }

  function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
    return <ul>{items.map(item => <li key={keyExtractor(item)}>{renderItem(item)}</li>)}</ul>;
  }

  // Ishlatish — TS turni ANGLAYDI (User yoki Product):
  <List
    items={users}                                // User[]
    renderItem={(user) => user.name}             // user — User (TS biladi, autocomplete)
    keyExtractor={(user) => user.id}
  />
  //  items User[] bo'lsa — renderItem'dagi user AVTOMATIK User turida (type-safe)

  ┌────────────────────────────────────────────────────────────┐
  │ Generic komponent: <T> — har tur bilan, lekin type-safe     │
  │ (List<User>, List<Product> — bir komponent, turli tur)      │
  └────────────────────────────────────────────────────────────┘

   Generic komponent — qayta ishlatiladigan + type-safe (List, Table, Select, Combobox)
   items turidan renderItem item turini ANGLAYDI (autocomplete + tekshiruv)

Generic komponentlar — har qanday tur bilan ishlaydigan, lekin type-safe komponentlar (7.3 — generics React'da). Misol — List<T>: interface ListProps<T> { items: T[]; renderItem: (item: T) => React.ReactNode; keyExtractor: (item: T) => string | number }T generic tur (har qanday bo'lishi mumkin). Komponent ham generic: function List<T>({ items, renderItem, keyExtractor }: ListProps<T>). Ishlatishda TypeScript turni anglaydi: <List items={users} renderItem={(user) => user.name} ... />items User[] bo'lganda, renderItemdagi user avtomatik User turida (autocomplete — user.name, user.email taklif qilinadi, va user.xyz xato). Bir xil List komponenti User[], Product[], Order[] — har tur bilan, lekin har birida type-safe. Ikki nuqta: (1) generic komponent — qayta ishlatiladigan + type-safe birikmasi (List, Table, Select, Combobox, DataGrid — universal komponentlar); (2) eng kuchli tomoni — items turidan TS renderItem/keyExtractordagi element turini avtomatik anglaydi (turni ikki marta yozish kerak emas, va mos kelmaslik — compile xatosi). Bu — kutubxona darajasidagi universal komponentlarni type-safe qurishning usuli.

2.10. Custom hook turlari

text
  CUSTOM HOOK 11.7-bob — qaytarish turini belgilash (yoki inference):

  // 1. INFERENCE (TS qaytarish turini o'zi anglaydi — ko'pincha yetadi):
  function useToggle(initial = false) {
    const [on, setOn] = useState(initial);
    const toggle = useCallback(() => setOn(o => !o), []);
    return [on, toggle] as const;        //  as const — tuple turi ([boolean, () => void])
  }
  const [isOpen, toggle] = useToggle();  // isOpen: boolean, toggle: () => void (type-safe)

  // 2. ANIQ QAYTARISH TURI (obyekt — murakkab hook):
  interface UseFetchResult<T> {
    data: T | null;
    loading: boolean;
    error: string | null;
  }
  function useFetch<T>(url: string): UseFetchResult<T> {   // generic — har tur uchun
    const [data, setData] = useState<T | null>(null);
    // ...
    return { data, loading, error };
  }
  const { data } = useFetch<User[]>("/api/users");   // data: User[] | null (type-safe)

   as const — massiv qaytaranda tuple turi (useState kabi [value, setter] — aniq turlar)
   Generic hook — useFetch<User[]> — qaytgan data turini chaqiruvchi belgilaydi (type-safe)

Custom hook turlari — custom hook'larni 11.7-bob type-safe qilish. (1) Inference — TS qaytarish turini ko'pincha o'zi anglaydi: function useToggle(initial = false) { ...; return [on, toggle] as const } — diqqat: as const muhim — usiz TS [on, toggle]ni (boolean | (() => void))[] (aralash massiv) deb biladi, as const bilan tuple ([boolean, () => void]) — aniq turlar (xuddi useState kabi [value, setter]). (2) Aniq qaytarish turi — murakkab hook (obyekt qaytaradigan) uchun interface: interface UseFetchResult<T> { data: T | null; loading: boolean; error: string | null }, va generic hook: function useFetch<T>(url: string): UseFetchResult<T>useFetch<User[]>("/api/users") data: User[] | null (type-safe). Ikki nuqta: (1) as const — massiv qaytaradigan hook'da tuple turi uchun zarur (aks holda destructuring noto'g'ri turlanadi); (2) generic hookuseFetch<User[]> — chaqiruvchi qaytgan ma'lumot turini belgilaydi (data avtomatik to'g'ri turda — autocomplete va tekshiruv). Bu — custom hook'larni butun loyiha bo'ylab type-safe qiladi (qaytgan qiymat turi har doim aniq).

2.11. React.FC munozarasi — nega ko'pincha ishlatilmaydi

text
  React.FC (FunctionComponent) — komponent turini belgilashning ESKI usuli:

  // React.FC bilan (eski — endi KAM tavsiya):
  const Button: React.FC<ButtonProps> = ({ text }) => <button>{text}</button>;

  // To'g'ridan props turi bilan (ZAMONAVIY tavsiya):
  function Button({ text }: ButtonProps) { return <button>{text}</button>; }

  NEGA React.FC KAM ISHLATILADI (2026):
   Ilgari children'ni AVTOMATIK qo'shardi (endi yo'q — React 18'da olib tashlandi)
   Generic komponentlar bilan noqulay (React.FC<Props<T>> — chalkash)
   Ortiqcha (props turini to'g'ridan yozish — soddaroq, aniqroq)

  TAVSIYA: to'g'ridan props turi (function Button({...}: Props) yoki const arrow)
   children kerak bo'lsa — Props ichida aniq yoz (children: ReactNode — 2.4)

   React.FC — eski uslub (zarari yo'q, lekin ortiqcha); ZAMONAVIY — to'g'ridan props turi
   Bu — munozara mavzu; jamoa izchilligi muhim (lekin ko'pchilik React.FC'dan voz kechdi)

React.FC munozarasi — React + TypeScript'ning eng ko'p munozara qilingan mavzusi. React.FC (FunctionComponent) — komponent turini belgilashning eski usuli: const Button: React.FC<ButtonProps> = ({ text }) => .... Zamonaviy tavsiya — to'g'ridan props turi: function Button({ text }: ButtonProps) {...} (yoki arrow function bilan const Button = ({ text }: ButtonProps) => ...). Nega React.FC kam ishlatiladi (2026): (1) ilgari childrenni avtomatik qo'shardi (qulay edi), lekin React 18'da bu olib tashlandi (endi React.FC childrenni avtomatik bermaydi — afzalligi yo'qoldi); (2) generic komponentlar bilan noqulay (React.FC<Props<T>> — chalkash); (3) ortiqcha — props turini to'g'ridan yozish soddaroq va aniqroq. Tavsiya: to'g'ridan props turi (function Button({...}: Props)); children kerak bo'lsa — Props ichida aniq yozing (children: ReactNode — 2.4) yoki PropsWithChildren. Ikki nuqta: (1) React.FC — eski uslub (zarari yo'q, lekin ortiqcha); zamonaviy React jamiyati to'g'ridan props turini afzal ko'radi; (2) bu munozara mavzu — jamoa izchilligi muhim (bir uslubni tanlab, unga rioya qiling), lekin yangi loyihada React.FCsiz boshlash tavsiya etiladi. Bu — amaliy, ko'p uchraydigan dizayn qarori.

2.12. Utility types React'da — Omit, Pick, Partial

text
  UTILITY TYPES 7.4-bob React props bilan juda foydali (mavjud turni qayta ishlatish):

  // HTML element props'ini KENGAYTIRISH (button'ning barcha props'i + o'zimizniki):
  interface ButtonProps extends React.ComponentProps<"button"> {   //  barcha <button> props
    variant: "primary" | "danger";          // + o'z props'imiz
  }
  //  onClick, disabled, type, className... HAMMASI avtomatik (qo'lda yozMASDAN)

  // OMIT (ba'zi props'ni OLIB tashlash):
  type InputProps = Omit<React.ComponentProps<"input">, "size"> & { size: "sm" | "lg" };
  //  input'ning barcha props'i, LEKIN "size"ni o'zimizniki bilan almashtirish

  // PICK (faqat ba'zi props):
  type Coords = Pick<DOMRect, "top" | "left">;   // faqat top, left

  // PARTIAL (barcha props ixtiyoriy — tahrirlash/yangilash):
  function updateUser(id: string, data: Partial<User>) {...}   // User'ning ba'zi maydonlari

   React.ComponentProps<"button"> — element'ning BARCHA props'ini beradi (kengaytirish uchun)
   Omit/Pick/Partial — mavjud turni moslab qayta ishlatish (7.4 — DRY)

Utility types React'da — TypeScript utility types 7.4-bob React props bilan juda foydali (mavjud turni qayta ishlatish — DRY). React.ComponentProps<"button"> — HTML element'ning barcha props'ini beradi: interface ButtonProps extends React.ComponentProps<"button"> { variant: "primary" } — bu Buttonga <button>ning barcha standart props'ini (onClick, disabled, type, className, aria-*...) avtomatik qo'shadi (qo'lda yozish kerak emas) + o'z props'imiz (variant). Omit — ba'zi props'ni olib tashlash: Omit<React.ComponentProps<"input">, "size"> & { size: "sm" | "lg" } (input props'i, lekin sizeni o'zimizniki bilan almashtirish). Pick — faqat ba'zi props (Pick<DOMRect, "top" | "left">). Partial — barcha props ixtiyoriy (tahrirlash/yangilash — Partial<User> — User'ning ba'zi maydonlari). Ikki nuqta: (1) React.ComponentProps<"element"> — custom komponentga HTML element props'ini "meros qilish" uchun ideal (custom Input/Button — native input'ning barcha imkoniyatini oladi — <Input onChange={...} disabled placeholder="..." />); (2) Omit/Pick/Partial — mavjud turni moslab qayta ishlatish (DRY — 7.4). Bu — kutubxona darajasidagi komponentlarni to'liq type-safe va native HTML bilan mos qiladi.

2.13. Context va Zod + TS birikmasi

text
  CONTEXT TURI — createContext'ga tur berish (11.5: 2.11):
  interface AuthContextType {
    user: User | null;
    login: (creds: Credentials) => Promise<void>;
    logout: () => void;
  }
  const AuthContext = createContext<AuthContextType | null>(null);   // null boshlang'ich

  // Custom hook — null tekshiruv bilan (type-safe):
  function useAuth() {
    const ctx = useContext(AuthContext);
    if (!ctx) throw new Error("useAuth AuthProvider ichida");   // null  xato (TS: ctx endi AuthContextType)
    return ctx;                                                  // tur: AuthContextType (null emas)
  }

  ZOD + TS (11.10 davomi) — sxema  tur (single source — 5.9):
  const userSchema = z.object({ id: z.string(), name: z.string(), age: z.number() });
  type User = z.infer<typeof userSchema>;          // sxemadan tur (qo'lda interface yo'q)
  // API javobini tekshirish + turlash (type-safe):
  const user: User = userSchema.parse(await res.json());   // runtime tekshiruv + compile turi

   createContext<T | null>(null) + hook'da null tekshiruv (type-safe Context)
   z.infer — sxemadan tur (validatsiya + tur bir manba — 5.9, 11.10)

Context va Zod + TS birikmasi — ikki muhim integratsiya. Context turi (11.5: 2.11): createContext<AuthContextType | null>(null) — tur generic argument sifatida (boshlang'ich null); custom hook'da null tekshiruv: function useAuth() { const ctx = useContext(AuthContext); if (!ctx) throw new Error(...); return ctx }if (!ctx) throw dan keyin TypeScript ctxni AuthContextType (null emas) deb biladi (type narrowing — 7.5), shuning uchun ishlatishda null tekshiruv kerak emas. Zod + TS (11.10 davomi, 5.9): const userSchema = z.object({...}) type User = z.infer<typeof userSchema> — sxemadan tur avtomatik (qo'lda interface yozish kerak emas, sxema = yagona manba); va API javobini tekshirish + turlash — const user: User = userSchema.parse(await res.json()) (runtime validatsiya + compile-time tur — ham server javobi to'g'riligini tekshiradi, ham type-safe qiladi). Ikki nuqta: (1) ContextcreateContext<T | null>(null) + hook'da null tekshiruv (type-safe va xato xabari bilan — 11.7: Misol 14); (2) Zodz.infer bilan sxemadan tur (validatsiya va tur bir manba — full-stack izchillik, 5.9, 11.10), va parse bilan runtime API javobini xavfsiz qilish. Bu — to'liq type-safe React ilovasining yakuniy bog'lanishi (komponent hook Context API — hammasi turlangan).

2.14. JSX.Element vs ReactNode, ComponentProps, Record

text
  QAYTARISH TURI — komponent nima qaytaradi (JSX.Element vs ReactNode):

  function A(): JSX.Element { return <div />; }      //  AYNAN bitta element
  function B(): React.ReactNode { return <div />; }  //  keng (fragment, string, null ham)
  //  ODATDA qaytarish turini QO'LDA yozmang — TS o'zi anglaydi (inference eng yaxshi)

  JSX.Element vs ReactNode (farq):
  - JSX.Element  — faqat bitta JSX element (React.createElement natijasi)
  - ReactNode    — element + string + number + array + null + boolean (KENGROQ)
   children uchun ReactNode 2.4-bob; qaytarish uchun — inference (qo'lda yozish shart emas)

  ComponentProps<typeof X> — MAVJUD komponent props turini olish (qayta e'lon qilmasdan):
  function Button(props: { text: string; variant: "a" | "b" }) {...}
  type ButtonProps = React.ComponentProps<typeof Button>;   // { text; variant } — avtomatik
  //  o'rovchi/HOC komponent yozganda foydali (props'ni takrorlamaslik)

  Record<K, V> — kalitqiymat xaritasi props uchun:
  interface Props {
    styles: Record<string, string>;                 // { [key]: string } — CSS obyekti
    labels: Record<"uz" | "en", string>;             // FAQAT shu kalitlar (majburiy)
  }

   Qaytarish turini yozmang — inference (JSX.Element/ReactNode qo'lda kamdan-kam)
   ComponentProps<typeof X> — mavjud komponent props'ini olish (DRY — 2.12 davomi)
   Record<K, V> — xarita props (kalit turi + qiymat turi bir joyda)

JSX.Element vs ReactNode, ComponentProps<typeof X>, Record — uchta amaliy nozik nuqta. (1) Qaytarish turi — komponent nima qaytaradi: JSX.Element (aynan bitta JSX element) yoki React.ReactNode (kengroq — element, string, number, array, null, boolean). Farq: children uchun ReactNode ishlatiladi (2.4 — hamma narsani qamraydi), lekin komponent qaytarish turini odatda qo'lda yozmaysiz — TS uni inference bilan o'zi aniqlaydi (bu eng ishonchli, chunki fragment yoki shartli null qaytarsangiz ham to'g'ri turlaydi). Faqat kerak bo'lsa, ReactNodeni afzal ko'ring (JSX.Element juda tor — fragment yoki null bilan xato beradi). (2) ComponentProps<typeof X>mavjud komponentning props turini qayta e'lon qilmasdan olish: type ButtonProps = React.ComponentProps<typeof Button>Button props interface'i export qilinmagan bo'lsa ham, uni oladi (o'rovchi komponent, HOC, yoki wrapper yozganda props'ni takrorlamaslik uchun ideal — DRY, 2.12 davomi). (3) Record<K, V> — kalitqiymat xaritasi turi: Record<string, string> (ixtiyoriy string kalitlar — masalan inline CSS obyekti), yoki Record<"uz" | "en", string> (aniq kalitlar — ikkalasi ham majburiy, biror til yo'q bo'lsa — xato). Uch nuqta: (1) komponent qaytarish turini yozmang — inference eng yaxshi; (2) ComponentProps<typeof X> — mavjud komponentdan props "meros" olish; (3) Record — lug'at/xarita shaklidagi props uchun (i18n label'lar, config obyektlari). Bu — kundalik amaliyotda tez-tez uchraydigan uchta nozik tur.

2.15. forwardRef turlari — ref uzatuvchi komponent

text
  forwardRef (11.5: 2.14) — komponentga tashqaridan ref berish, TIP bilan:

  interface InputProps {
    label: string;
    error?: string;
  }
  // forwardRef<REF_TURI, PROPS_TURI> — ikki generic argument:
  const Input = React.forwardRef<HTMLInputElement, InputProps>(
    ({ label, error }, ref) => {                    // ref — ikkinchi argument
      return (
        <div>
          <label>{label}</label>
          <input ref={ref} aria-invalid={!!error} />   {/* ref shu <input>'ga */}
        </div>
      );
    }
  );
  Input.displayName = "Input";                        // devtools uchun (arrow — nom yo'q)

  // Ishlatish — ref type-safe (HTMLInputElement):
  const ref = useRef<HTMLInputElement>(null);
  <Input ref={ref} label="Email" />                   // ref.current — HTMLInputElement | null

   forwardRef<ElementTuri, PropsTuri> — birinchi = ref turi, ikkinchi = props
   displayName — arrow funksiyada nom yo'q (devtools "ForwardRef" o'rniga aniq nom)
   React 19'da forwardRef kerak emas — ref oddiy prop bo'ldi (versiyaga qarab)

forwardRef turlari — ref'ni ota-komponentdan bola-komponent ichidagi DOM element'ga uzatuvchi komponent (11.5: 2.14), tip bilan. React.forwardRef ikki generic argument oladi: birinchi — ref element turi (HTMLInputElement), ikkinchi — props turi (InputProps): React.forwardRef<HTMLInputElement, InputProps>((props, ref) => ...). Funksiya ichida ref ikkinchi argument sifatida keladi va uni bola element'ga uzatasiz (<input ref={ref} />). displayName qo'shish tavsiya etiladi (Input.displayName = "Input") — arrow funksiyada nom bo'lmagani uchun React DevTools'da "ForwardRef" o'rniga aniq nom ko'rsatiladi. Ishlatishda ref to'liq type-safe: const ref = useRef<HTMLInputElement>(null); <Input ref={ref} ... />ref.current avtomatik HTMLInputElement | null turida. Uch nuqta: (1) forwardRef<ElementTuri, PropsTuri> — argumentlar tartibi teskari (avval ref turi, keyin props — chalkashmang); (2) displayName qo'shing (devtools uchun); (3) muhim versiya farqi — React 19'dan boshlab forwardRef kerak emas, ref oddiy props sifatida uzatiladi (function Input({ label, ref }: InputProps & { ref?: React.Ref<HTMLInputElement> })) — lekin ko'p loyiha hali React 18'da, shuning uchun forwardRefni bilish shart. Bu — dizayn-tizim (design system) komponentlarining (Input, Button) muhim qismi.

2.16. Polymorphic komponent — as prop, ElementType

text
  POLYMORPHIC KOMPONENT — turli HTML teg'da render bo'ladigan komponent (as prop):

  // Oddiy holat (ElementType — har qanday teg/komponent):
  interface TextProps {
    as?: React.ElementType;              // qaysi teg: "h1", "p", "span", Link...
    children: React.ReactNode;
  }
  function Text({ as: Component = "span", children }: TextProps) {
    return <Component>{children}</Component>;         // as  render'da teg
  }
  <Text as="h1">Sarlavha</Text>          // <h1> bo'lib render
  <Text as="p">Matn</Text>               // <p> bo'lib render

  // TO'LIQ TYPE-SAFE polymorphic (as teg props'ini ham to'g'ri oladi — ilg'or):
  type PolymorphicProps<E extends React.ElementType> = {
    as?: E;
    children: React.ReactNode;
  } & Omit<React.ComponentPropsWithoutRef<E>, "as" | "children">;   // teg'ning native props'i

  function Box<E extends React.ElementType = "div">({ as, ...rest }: PolymorphicProps<E>) {
    const Component = as || "div";
    return <Component {...rest} />;
  }
  <Box as="a" href="/uz">Havola</Box>    // href — <a>'da bor (type-safe); <button>'da xato

   as?: React.ElementType — komponent qaysi teg'da render bo'lishini tanlash (Button, Text, Box)
   ComponentPropsWithoutRef<E> — tanlangan teg'ning native props'i (as="a"  href, as="button"  type)
   Ilg'or naqsh — dizayn-tizim komponentlarida (bir Box, ko'p teg — type-safe)

Polymorphic komponent — bir komponent turli HTML teg (yoki boshqa komponent) sifatida render bo'ladi — as prop orqali tanlanadi. Oddiy holat: interface TextProps { as?: React.ElementType; children: React.ReactNode }React.ElementType har qanday teg ("h1", "p", "span") yoki komponentni qabul qiladi; ichida const Component = as; return <Component>{children}</Component><Text as="h1"> <h1> bo'lib render, <Text as="p"> <p>. Bu bitta Text/Box/Button komponentini turli semantik teg'da ishlatishga imkon beradi (dizayn-tizimning asosiy naqshi). To'liq type-safe (ilg'or) versiya generic bilan quriladi: function Box<E extends React.ElementType = "div">({ as, ...rest }: PolymorphicProps<E>) — bunda React.ComponentPropsWithoutRef<E> tanlangan teg'ning native props'ini ham to'g'ri turlaydi: <Box as="a" href="/uz">href <a>'da bor (ruxsat), lekin <Box as="button" href="...">href <button>'da yo'q (compile xatosi). Uch nuqta: (1) as?: React.ElementType — komponentga "qaysi teg'da render bo'lasiz" deb aytish (semantik moslashuvchanlik); (2) ComponentPropsWithoutRef<E> — tanlangan teg'ning props'ini avtomatik oladi (as="a" href, as="input" value); (3) bu ilg'or naqsh — dizayn-tizim kutubxonalarida (Chakra UI, Radix, MUI) keng ishlatiladi. ComponentPropsWithoutRef ComponentPropsdan farqi — u refni chiqarib tashlaydi (polymorphic'da ref alohida boshqariladi). Bu — kutubxona darajasidagi eng murakkab, lekin eng kuchli tiplash naqshi.

2.17. Type-safe loyiha tafakkuri

text
  TYPE-SAFE REACT LOYIHA (xulosa — qatlamma-qatlam turlash):

  ┌──────────────────────────────────────────────────────────┐
  │ Komponent props (interface — 2.3)                          │
  │                                                             │
  │ Hooklar (useState<T>, custom hook — 2.5, 2.10)             │
  │                                                             │
  │ Context (createContext<T> — 2.13)                          │
  │                                                             │
  │ API qatlami (Zod schema + z.infer — 2.13, 5.9)            │
  │                                                             │
  │ Backend (bir xil Zod schema — 5.9 — full-stack type-safe)  │
  └──────────────────────────────────────────────────────────┘

  AMALIY MASLAHATLAR:
   strict: true (barcha himoya — 2.2)
   any'dan qoch (unknown + tekshiruv yoki aniq tur — 7.5)
   Inference'ga ishon (oddiy holatda qo'lda tur yozma — 2.5)
   Zod API chegarasida (server javobi — runtime + tur — 2.13)
   React.FC emas, to'g'ridan props turi (2.11)

   Type-safe — komponentdan API'gacha (va backend'gacha — Zod) ZANJIR (full-stack)
   TS — "to'sqinlik" emas, YORDAMCHI (xato erta, autocomplete, ishonchli refactoring)

Type-safe loyiha tafakkuri — bobning yakuniy xulosasi. Type-safe React loyiha qatlamma-qatlam turlanadi: komponent props (interface — 2.3) hooklar (useState<T>, custom hook — 2.5, 2.10) Context (createContext<T> — 2.13) API qatlami (Zod schema + z.infer — 2.13) backend (bir xil Zod schema — 5.9 — full-stack type-safe). Ya'ni ma'lumot serverdan komponentga qadar har qatlamda turlangan (mos kelmaslik — compile xatosi). Amaliy maslahatlar: strict: true (barcha himoya — 2.2); anydan qoch (unknown + tekshiruv yoki aniq tur — 7.5 — any TypeScript himoyasini o'chiradi); inference'ga ishon (oddiy holatda qo'lda tur yozma — 2.5); Zod'ni API chegarasida ishlat (server javobi — runtime + tur — 2.13); React.FC emas, to'g'ridan props turi 2.11-bob. Ikki yakuniy tamoyil: (1) type-safe — komponentdan API'gacha (va backend'gacha — Zod) zanjir (full-stack — ma'lumot oqimi butunlay xavfsiz); (2) TypeScript — "to'sqinlik" emas, yordamchi: u xatolarni erta tutadi, autocomplete beradi, refactoring'ni xavfsiz qiladi — boshida biroz ko'proq yozasiz, lekin ko'p marta ko'proq vaqt va xatoni tejaysiz. Bu — professional React loyihasining poydevori.


3. Sintaksis — tez ma'lumotnoma

text
PROPS 2.3-bob:       interface Props { name: string; variant: "a"|"b"; opt?: boolean }
                   function C({ name }: Props) {...}
CHILDREN 2.4-bob:    children: React.ReactNode  |  React.PropsWithChildren<Props>
useState 2.5-bob:    useState(0)  |  useState<User|null>(null)  |  useState<T[]>([])
useRef 2.6-bob:      useRef<HTMLInputElement>(null)  |  useRef<number>(0)
useReducer 2.7-bob:  type Action = {type:"x"} | {type:"set"; payload:number}  // discriminated union
EVENT 2.8-bob:       e: React.ChangeEvent<HTMLInputElement>  |  React.FormEvent<HTMLFormElement>
GENERIC 2.9-bob:     function List<T>({ items }: ListProps<T>) {...}
HOOK 2.10-bob:       return [a, b] as const  |  function useFetch<T>(): Result<T>
HTML PROPS 2.12-bob: extends React.ComponentProps<"button">  |  Omit<...,"size">
CONTEXT 2.13-bob:    createContext<T | null>(null)  +  if (!ctx) throw
ZOD 2.13-bob:        type User = z.infer<typeof userSchema>  |  schema.parse(data)
COMPPROPS 2.14-bob:  React.ComponentProps<typeof Button>  |  Record<"a"|"b", string>
forwardRef 2.15-bob: React.forwardRef<HTMLInputElement, Props>((props, ref) => ...)
POLYMORPH 2.16-bob:  as?: React.ElementType  |  ComponentPropsWithoutRef<E>  (as prop)

4. Batafsil kod namunalari

Misol 1 — Komponent props (interface — 2.3)

tsx
interface ButtonProps {
  text: string;
  variant: "primary" | "danger" | "ghost";   // union — faqat shu qiymatlar
  disabled?: boolean;                          // ixtiyoriy
  onClick: () => void;
}

function Button({ text, variant, disabled = false, onClick }: ButtonProps) {
  return (
    <button className={`btn btn-${variant}`} disabled={disabled} onClick={onClick}>
      {text}
    </button>
  );
}

// Ishlatish — type-safe:
<Button text="Saqlash" variant="primary" onClick={() => {}} />   // 
// <Button text="X" variant="warning" />   //  "warning" union'da yo'q + onClick yetishmaydi

Misol 2 — children turi (2.4)

tsx
interface CardProps {
  title: string;
  children: React.ReactNode;        // JSX, matn, array... (hammasi)
  footer?: React.ReactNode;         // ixtiyoriy children-kabi prop
}

function Card({ title, children, footer }: CardProps) {
  return (
    <div className="card">
      <h3>{title}</h3>
      <div className="body">{children}</div>
      {footer && <div className="footer">{footer}</div>}
    </div>
  );
}
// Yoki PropsWithChildren bilan:
// function Card({ title, children }: React.PropsWithChildren<{ title: string }>) {...}

Misol 3 — useState turlari (2.5)

tsx
interface User { id: string; name: string; }

function Component() {
  const [count, setCount] = useState(0);                    // number (inference)
  const [name, setName] = useState("");                     // string
  const [user, setUser] = useState<User | null>(null);      // generic (null boshlang'ich)
  const [items, setItems] = useState<User[]>([]);           // generic (bo'sh massiv)
  const [status, setStatus] = useState<"idle" | "loading" | "done">("idle");   // union

  setUser({ id: "1", name: "Ali" });   //  type-safe
  // setUser({ id: "1" });             //  name yetishmaydi
  return null;
}

Misol 4 — useRef turlari (2.6)

tsx
function SearchForm() {
  const inputRef = useRef<HTMLInputElement>(null);   // DOM ref
  const timerRef = useRef<number | null>(null);      // mutable (interval ID)

  useEffect(() => {
    inputRef.current?.focus();                        // ?. — null bo'lishi mumkin (2.6)
  }, []);

  const startTimer = () => {
    timerRef.current = window.setInterval(() => console.log("tick"), 1000);
  };
  const stopTimer = () => {
    if (timerRef.current) clearInterval(timerRef.current);
  };

  return <input ref={inputRef} />;
}

Misol 5 — useReducer turlari (discriminated union — 2.7)

tsx
interface State { count: number; loading: boolean; }

type Action =
  | { type: "increment" }
  | { type: "decrement" }
  | { type: "set"; payload: number }
  | { type: "setLoading"; payload: boolean };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "increment": return { ...state, count: state.count + 1 };
    case "decrement": return { ...state, count: state.count - 1 };
    case "set": return { ...state, count: action.payload };          // payload: number (TS biladi)
    case "setLoading": return { ...state, loading: action.payload }; // payload: boolean
    default: return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0, loading: false });
  return (
    <div>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "set", payload: 100 })}>100</button>
      {/* dispatch({ type: "set" }) —  payload talab qilinadi (type-safe) */}
    </div>
  );
}

Misol 6 — Event turlari (2.8)

tsx
function Form() {
  const [value, setValue] = useState("");

  // Alohida funksiya — qo'lda tur
  function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    setValue(e.target.value);
  }
  function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    console.log(value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={value} onChange={handleChange} />
      {/* Inline — TS o'zi anglaydi (qo'lda tur kerak emas): */}
      <input onChange={(e) => setValue(e.target.value)} />
      <button onClick={(e) => e.preventDefault()}>Yuborish</button>
    </form>
  );
}

Misol 7 — Generic komponent: List (2.9)

tsx
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
  keyExtractor: (item: T) => string | number;
}

function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
  if (items.length === 0) return <p>Bo'sh</p>;
  return <ul>{items.map(item => <li key={keyExtractor(item)}>{renderItem(item)}</li>)}</ul>;
}

// Ishlatish — TS turni anglaydi:
interface Product { id: string; name: string; price: number; }
<List<Product>
  items={products}
  renderItem={(p) => `${p.name}${p.price}`}   // p: Product (autocomplete)
  keyExtractor={(p) => p.id}
/>

Misol 8 — Custom hook turi (2.10)

tsx
// Tuple qaytaruvchi (as const):
function useToggle(initial = false) {
  const [on, setOn] = useState(initial);
  const toggle = useCallback(() => setOn(o => !o), []);
  return [on, toggle] as const;        // [boolean, () => void] (tuple)
}
const [isOpen, toggle] = useToggle();  // isOpen: boolean, toggle: () => void

// Generic obyekt qaytaruvchi:
interface FetchResult<T> { data: T | null; loading: boolean; error: string | null; }

function useFetch<T>(url: string): FetchResult<T> {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  useEffect(() => {
    fetch(url).then(r => r.json()).then((d: T) => { setData(d); setLoading(false); });
  }, [url]);
  return { data, loading, error };
}

const { data } = useFetch<Product[]>("/api/products");   // data: Product[] | null

Misol 9 — HTML element props kengaytirish (2.12)

tsx
// Custom Input — <input>'ning BARCHA props'i + o'zimizniki:
interface InputProps extends React.ComponentProps<"input"> {
  label: string;
  error?: string;
}

function Input({ label, error, ...rest }: InputProps) {
  return (
    <div className="field">
      <label>{label}</label>
      <input {...rest} aria-invalid={!!error} />   {/* native props: onChange, placeholder, disabled... */}
      {error && <span className="error">{error}</span>}
    </div>
  );
}

// Ishlatish — native input props avtomatik:
<Input label="Email" type="email" placeholder="email@x.uz" onChange={(e) => {}} required />
//  onChange/type/placeholder/required — ComponentProps<"input">'dan (qo'lda yozMASDAN — 2.12)

Misol 10 — Utility types: Omit, Partial (2.12)

tsx
interface User { id: string; name: string; email: string; password: string; role: "user" | "admin"; }

// Yangi user yaratish — id yo'q (server beradi), password kerak:
type CreateUserDto = Omit<User, "id">;                    // id'siz

// Tahrirlash — barcha maydon ixtiyoriy (faqat o'zgarganini yubor):
type UpdateUserDto = Partial<Omit<User, "id" | "password">>;   // id/password'siz, hammasi ixtiyoriy

// Public user — parolsiz (xavfsizlik):
type PublicUser = Omit<User, "password">;

function updateUser(id: string, data: UpdateUserDto) { /* ... */ }
updateUser("1", { name: "Yangi" });    //  faqat name (Partial — ixtiyoriy)

Misol 11 — Context turi (2.13)

tsx
interface User { id: string; name: string; }
interface AuthContextType {
  user: User | null;
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
}

const AuthContext = createContext<AuthContextType | null>(null);   // null boshlang'ich

export function AuthProvider({ children }: React.PropsWithChildren) {
  const [user, setUser] = useState<User | null>(null);
  const login = async (email: string, password: string) => { /* ... */ setUser({ id: "1", name: "Ali" }); };
  const logout = () => setUser(null);
  return <AuthContext.Provider value={{ user, login, logout }}>{children}</AuthContext.Provider>;
}

export function useAuth(): AuthContextType {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth AuthProvider ichida ishlatilishi kerak");   // null tekshiruv
  return ctx;                                                                     // tur: AuthContextType
}

Misol 12 — Discriminated union props (2.7, 7.4)

tsx
// Komponent ikki rejimda — TS to'g'ri props'ni talab qiladi:
type AlertProps =
  | { variant: "success"; message: string }
  | { variant: "error"; message: string; retry: () => void };   // error'da retry MAJBURIY

function Alert(props: AlertProps) {
  return (
    <div className={`alert alert-${props.variant}`}>
      <p>{props.message}</p>
      {props.variant === "error" && <button onClick={props.retry}>Qayta</button>}   {/* retry — faqat error'da */}
    </div>
  );
}

<Alert variant="success" message="Saqlandi" />                      // 
<Alert variant="error" message="Xato" retry={() => {}} />           // 
// <Alert variant="error" message="Xato" />                        //  retry yetishmaydi

Misol 13 — Zod + TS (sxema tur — 2.13)

tsx
import { z } from "zod";

const productSchema = z.object({
  id: z.string(),
  name: z.string(),
  price: z.number().positive(),
  inStock: z.boolean(),
});

type Product = z.infer<typeof productSchema>;        // sxemadan tur (qo'lda interface yo'q)
const productsSchema = z.array(productSchema);

async function getProducts(): Promise<Product[]> {
  const res = await fetch("/api/products");
  const data = await res.json();
  return productsSchema.parse(data);                 // runtime tekshiruv + tur (xato bo'lsa throw)
}
//  z.infer — bir manba (validatsiya + tur); parse — server javobini xavfsiz qiladi (5.9, 11.10)

Misol 14 — To'liq type-safe komponent (hammasi birga)

tsx
import { z } from "zod";

const userSchema = z.object({ id: z.string(), name: z.string(), role: z.enum(["user", "admin"]) });
type User = z.infer<typeof userSchema>;

interface UserCardProps extends React.ComponentProps<"div"> {   // div props + o'zimizniki
  user: User;
  onSelect?: (id: string) => void;
}

function UserCard({ user, onSelect, ...rest }: UserCardProps) {
  const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
    onSelect?.(user.id);
  };
  return (
    <div {...rest} className="user-card" onClick={handleClick}>
      <h3>{user.name}</h3>
      <span className={`badge badge-${user.role}`}>{user.role}</span>   {/* role: "user"|"admin" */}
    </div>
  );
}

// Generic ro'yxat bilan birga:
function UserList({ users }: { users: User[] }) {
  return (
    <List<User>
      items={users}
      renderItem={(u) => <UserCard user={u} onSelect={(id) => console.log(id)} />}
      keyExtractor={(u) => u.id}
    />
  );
}
//  Zod (tur) + interface (props) + ComponentProps (native) + event tur + generic — to'liq type-safe

Misol 15 — forwardRef va ComponentProps (2.15, 2.14)

tsx
interface InputProps {
  label: string;
  error?: string;
}

// forwardRef<ref turi, props turi> — ref uzatuvchi komponent:
const Input = React.forwardRef<HTMLInputElement, InputProps>(
  ({ label, error }, ref) => (
    <div className="field">
      <label>{label}</label>
      <input ref={ref} aria-invalid={!!error} />   {/* ref shu <input>'ga */}
      {error && <span className="error">{error}</span>}
    </div>
  )
);
Input.displayName = "Input";   // devtools uchun (arrow — nom yo'q)

// Mavjud komponent props turini olish (qayta e'lon qilmasdan):
type InputPublicProps = React.ComponentProps<typeof Input>;   // { label; error? } + ref

// Ishlatish — ref type-safe:
function Form() {
  const inputRef = useRef<HTMLInputElement>(null);
  useEffect(() => inputRef.current?.focus(), []);   // ref.current: HTMLInputElement | null
  return <Input ref={inputRef} label="Email" />;
}
//  React 19'da forwardRef kerak emas (ref oddiy prop) — React 18'da esa shu naqsh (2.15)

Misol 16 — Polymorphic komponent: as prop (2.16)

tsx
// To'liq type-safe polymorphic Box — as teg'ning native props'ini ham oladi:
type PolymorphicProps<E extends React.ElementType> = {
  as?: E;
  children?: React.ReactNode;
} & Omit<React.ComponentPropsWithoutRef<E>, "as" | "children">;

function Box<E extends React.ElementType = "div">({ as, children, ...rest }: PolymorphicProps<E>) {
  const Component = as || "div";
  return <Component {...rest}>{children}</Component>;
}

// Ishlatish — as teg'ga qarab native props type-safe:
<Box>oddiy div</Box>                                   // <div>
<Box as="a" href="/uz">Havola</Box>                    // href — <a>'da bor 
<Box as="button" type="submit" onClick={() => {}}>Yuborish</Box>   // type/onClick — <button>'da 
// <Box as="button" href="/x" />                       //  href <button>'da yo'q (type-safe)

Misol 17 — Record props: i18n label'lar (2.14)

tsx
type Lang = "uz" | "en";

interface LabeledProps {
  lang: Lang;
  // Record<K, V> — har til uchun matn MAJBURIY (biror til yo'q bo'lsa — compile xatosi):
  labels: Record<Lang, string>;
  styles?: Record<string, string>;   // ixtiyoriy kalitlar (inline CSS obyekti)
}

function Labeled({ lang, labels, styles }: LabeledProps) {
  return <span style={styles}>{labels[lang]}</span>;   // labels[lang] — string (type-safe)
}

<Labeled
  lang="uz"
  labels={{ uz: "Saqlash", en: "Save" }}   // ikki til ham majburiy
  styles={{ color: "red", fontWeight: "bold" }}
/>
// <Labeled lang="uz" labels={{ uz: "Saqlash" }} />   //  "en" yetishmaydi (Record<Lang>)

5. To'g'ri va noto'g'ri holatlar

1) Props turi

text
 function C(props) {...}  (any — TS himoyasi yo'q)
 function C({ name }: Props) {...}  (interface — type-safe — 2.3)

2) useState null/bo'sh

text
 const [user, setUser] = useState(null);  (tur: null — setUser(realUser) xato)
 useState<User | null>(null)  (generic — 2.5)

3) any ishlatish

text
 const data: any = await res.json();  (TS himoyasi o'chadi — 2.17)
 Zod parse yoki aniq tur (unknown + tekshiruv — 2.13, 7.5)

4) React.FC

text
 const C: React.FC<Props> = ...  (eski, ortiqcha — 2.11)
 function C({ ... }: Props) {...}  (to'g'ridan props turi)

5) Event turi

text
 function h(e: any) {...}  (e.target.value — any, himoya yo'q)
 e: React.ChangeEvent<HTMLInputElement>  (2.8)

6) Custom hook tuple

text
 return [on, toggle]  (tur: (boolean | fn)[] — destructuring noto'g'ri)
 return [on, toggle] as const  (tuple — 2.10)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — Type 'null' is not assignable to type 'User'

Sababi: useState(null) — tur null deb anglandi, keyin setUser(realUser) xato 2.5-bob. Yechimi: useState<User | null>(null).

Xato 2 — Object is possibly 'null' (ref/context)

Sababi: ref.current yoki context null bo'lishi mumkin (strict mode — 2.6, 2.13). Yechimi: ref.current?.focus() (optional chaining), yoki context'da if (!ctx) throw.

Xato 3 — Property 'value' does not exist on type 'EventTarget'

Sababi: event turi noto'g'ri yoki yo'q 2.8-bob. Yechimi: e: React.ChangeEvent<HTMLInputElement> (element turini bering).

Xato 4 — Custom hook destructuring noto'g'ri tur

Sababi: return [a, b] — massiv (tuple emas — 2.10). Yechimi: return [a, b] as const.

Xato 5 — Parameter 'item' implicitly has an 'any' type

Sababi: generic komponent turi berilmagan, yoki noImplicitAny (2.9, strict). Yechimi: generic tur (List<T>), yoki argument turi bering.

Xato 6 — Props'ga className/onClick berib bo'lmaydi (custom komponent)

Sababi: props turi native HTML props'ni qamramaydi 2.12-bob. Yechimi: extends React.ComponentProps<"div"> (yoki mos element).

Xato 7 — any orqali xato yashirin o'tib ketdi

Sababi: any TypeScript himoyasini o'chiradi 2.17-bob. Yechimi: unknown + tekshiruv, yoki aniq tur, yoki Zod parse.


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • TypeScript (7-QISM): turlar, interface, generics, utility types — React'da qo'llanadi.
  • Komponent/props 11.2-bob: props turi — komponent shartnomasi.
  • Hooks (11.5, 11.6): useState/useRef/useReducer turlari (generic, union).
  • Forma + Zod 11.10-bob: z.infer — sxemadan tur (type-safe forma).
  • Context 11.5-bob: createContext + null tekshiruv (11.7 hook bilan).
  • Backend 5.9-bob: bir xil Zod schema — full-stack type-safe.
  • Custom hooks 11.7-bob: generic hook — type-safe qaytarish.
  • API qatlami 12.4-bob: TanStack Query — generic, type-safe ma'lumot.

8. Eng yaxshi amaliyotlar (best practices)

  • strict: true (barcha TS himoyasi — eng muhim sozlama — 2.2).
  • Props interface/type (har komponentga — autocomplete + tekshiruv — 2.3).
  • any'dan qoch (unknown + tekshiruv, aniq tur, Zod — 2.17, 7.5).
  • Inference'ga ishon (oddiy useState/event — qo'lda tur yozma — 2.5, 2.8).
  • Generic null/bo'sh state'ga (useState<T|null>, useState<T[]> — 2.5).
  • as const tuple hook'da (return [a, b] as const — 2.10).
  • ComponentProps<"el"> native HTML props meros qilishda 2.12-bob.
  • z.infer Zod bilan (sxema tur — bir manba — 2.13).
  • Context null tekshiruv (createContext<T|null> + hook throw — 2.13).
  • React.FC emas, props turi (to'g'ridan — soddaroq — 2.11).
  • Qaytarish turini yozmang (inference — JSX.Element/ReactNode qo'lda kamdan-kam — 2.14).
  • ComponentProps<typeof X> mavjud komponent props'ini olishda (DRY — 2.14).
  • forwardRef<El, Props> + displayName ref uzatuvchi komponentda 2.15-bob.
  • Polymorphic as prop dizayn-tizim komponentlarida (ElementType — 2.16).

9. Amaliy loyiha: "JavaScript loyihani TypeScript'ga ko'chirish"

Mavjud (yoki yangi) React loyihani to'liq type-safe qilib, TypeScript afzalliklarini amalda his qilish.

Maqsad

Kichik React ilovani (oldingi loyihalardan biri) TypeScript'ga ko'chiring yoki noldan TS bilan yozing — har qatlamni (komponent, hook, Context, API) type-safe qiling.

Talablar (requirements)

  1. Setup: react-ts shablon yoki mavjud loyihani .tsxga ko'chiring, strict: true 2.2-bob.
  2. Props turlari: har komponentga interface/type (union, optional — Misol 1, 2.3).
  3. children: o'rovchi komponentlarga React.ReactNode/PropsWithChildren (Misol 2, 2.4).
  4. Hooklar: useState generic (null/massiv), useRef DOM, useReducer discriminated union (Misol 3-5).
  5. Event: handler'larga to'g'ri event turi (Misol 6, 2.8).
  6. Generic komponent: kamida bitta (List/Table/Select — Misol 7, 2.9).
  7. Custom hook: type-safe (tuple as const yoki generic — Misol 8, 2.10).
  8. HTML props: kamida bitta komponent ComponentProps<"el"> bilan kengaytirsin (Misol 9, 2.12).
  9. Context: createContext<T|null> + null tekshiruvli hook (Misol 11, 2.13).
  10. Zod: API qatlamida z.infer + parse (type-safe + runtime — Misol 13, 2.13).

Maslahatlar (hint)

  • strict: trueni yoq — usiz TS'ning yarim foydasi yo'qoladi 2.2-bob.
  • anydan qoch — agar bilmasangiz unknown + tekshiruv (Xato 7).
  • Inference'ga ishon: oddiy useState(0)/inline event — qo'lda tur yozma (2.5, 2.8).
  • null/bo'sh state — generic kerak (useState<User|null>(null) — Xato 1).
  • React.FC ishlatma — to'g'ridan props turi 2.11-bob.
  • Zod sxemani backend bilan ulashishga tayyorla (bir manba — 5.9, 11.10).

"Tayyor" mezonlari (acceptance criteria)

  • strict: true, hech qanday any yo'q (yoki oqlangan).
  • Har komponent props turlangan.
  • children turlari to'g'ri (ReactNode).
  • Hooklar turlangan (generic null/massiv, discriminated union reducer).
  • Event handler'lar turlangan.
  • Generic komponent ishlaydi (type-safe).
  • Custom hook type-safe (tuple/generic).
  • Context null tekshiruvli hook bilan.
  • Zod API chegarasida (parse + infer).
  • Muharrir hech qanday TS xato ko'rsatmaydi (compile toza).

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda TypeScript va React birikmasini chuqur o'rgandik:

  • Nega TS (xato erta, autocomplete, refactoring — 2.1); setup (react-ts, strict — 2.2); props turlari 2.3-bob; children (ReactNode — 2.4).
  • Hooklar turlari (useState generic — 2.5, useRef — 2.6, useReducer discriminated union — 2.7); event turlari 2.8-bob; generic komponentlar 2.9-bob; custom hook 2.10-bob.
  • React.FC munozarasi 2.11-bob; utility types (ComponentProps, Omit, Partial — 2.12); Context va Zod 2.13-bob; JSX.Element vs ReactNode, ComponentProps, Record 2.14-bob; forwardRef 2.15-bob; polymorphic komponent (as, ElementType — 2.16); type-safe tafakkur 2.17-bob.

Endi siz komponentdan API qatlamigacha (va backend'gacha — Zod) to'liq type-safe React ilova yoza olasiz — xatolar compile paytida tutiladi, autocomplete tezligini oshiradi, refactoring xavfsiz. Bu — 2026 professional React loyihasining standarti.

Keyingi bob — 11.15-bob: Dashboard loyiha — layout, auth. Endi shu paytgacha o'rgangan barcha narsalarni (komponent, hooklar, routing, forma, performance, TypeScript) bitta real loyihada birlashtiramiz: professional dashboard. Layout pattern (sidebar + header + Outlet), responsive (mobil sidebar), autentifikatsiya oqimi (login token protected routes), API qatlami (axios instance + interceptors), CRUD sahifa naqshi, va production tayyorlik (error boundary + lazy + a11y). Bu — sizning portfoliongning markaziy loyihasi bo'lishi mumkin.


Foydalanilgan rasmiy/ishonchli manbalar

  • React rasmiy hujjati — "Using TypeScript" bo'limi: komponent va hook turlari, ReactNode, event turlari, Context tiplash.
  • TypeScript rasmiy hujjati — utility types (Partial, Pick, Omit, Record), generics, discriminated union, as const, type vs interface.
  • React + TypeScript Cheatsheet (jamoaviy ochiq qo'llanma) — props naqshlari, forwardRef, polymorphic komponent, ComponentProps/ComponentPropsWithoutRef.
  • Vite rasmiy hujjatireact-ts shabloni va loyiha sozlamalari (tsconfig, strict).
  • Zod rasmiy hujjati — sxema, z.infer, parse/safeParse (API chegarasida runtime validatsiya).
  • DefinitelyTyped (@types) — kutubxonalar uchun tur ta'riflari (@types/react, @types/node).

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
11.14-bob: TypeScript bilan React — Wisar