IlmHamroh
JavaScript Full-stack/15-qism. TypeScript26/47-dars20 daqiqa
Mundarija (35)

TypeScript utility types: Partial, Pick, Omit, ReturnType va boshqalar

Qisqacha: Utility types — TypeScript'ning tayyor "tur-funksiyalari": mavjud turdan yangisini yasaydi. Partial<Dish> — hamma maydon ixtiyoriy, Pick<Dish, "name"> — faqat tanlangan maydonlar, Omit<Dish, "id"> — ko'rsatilganlardan tashqari hammasi, ReturnType<typeof fn> — funksiya natijasining turi. Bitta asosiy tur yoziladi, uning variantlari esa undan chiqariladi.

Bu darsda

  • Obyekt turini o'zgartiradigan utility'lar: Partial, Required, Readonly, Pick, Omit, Record.
  • Union'ni filtrlaydiganlar: Exclude, Extract, NonNullable.
  • Funksiya va klassdan tur oladiganlar: ReturnType, Parameters, Awaited, InstanceType.
  • Omit ning kalit tekshirmasligi va Partial + spread tuzog'ini bilasiz.
  • vazifalar dagi api.ts ni so'rov tanalari utility types bilan yozilgan holda .ts ga ko'chirasiz.

Oldin bilishingiz kerak: keyof, typeof va indexed access, Generic interface, type va klass, Index signature va Record, Union va literal turlar.

1. Nega bu kerak?

O'tgan darsda turlarni qiymatlardan chiqardik. Endi turlarni boshqa turlardan yasaymiz. «Bahor» serverida taom bilan uch xil ish bor:

  • yaratish (POST): id ni server beradi, demak tanada id yo'q;
  • yangilash (PATCH): istalgan maydon kelishi mumkin, hammasi ixtiyoriy;
  • ro'yxat (GET): faqat nom va narx kerak.

Sardor uchala turni qo'lda yozdi:

ts
type Dish = { id: number; name: string; price: number };
type NewDish = { name: string; price: number };
type DishPatch = { name?: string; price?: number };
type DishRow = { name: string; price: number };

const patch: DishPatch = { price: 37000 };
console.log(patch); // { price: 37000 }

To'rtta tur — bitta ma'lumotning to'rt nusxasi. Ertaga Dish ga cookMinutes qo'shilsa, qolgan uchtasini ham yangilash kerak. Biri unutiladi — va server bilan kelishuv jim buziladi. Utility types bu nusxalarni formula bilan almashtiradi: NewDish = Omit<Dish, "id">.

2. Obyekt turini o'zgartiradiganlar

2.1 Partial<T> — hamma maydon ixtiyoriy

ts
type Dish = { id: number; name: string; price: number };
type DishPatch = Partial<Dish>;

function describePatch(patch: DishPatch): string {
  return Object.keys(patch).join(", ");
}
console.log(describePatch({ price: 37000 })); // price

Partial<Dish> — { id?: number; name?: string; price?: number }. PATCH so'rovi, forma qoralamasi, sozlamalarni qisman yangilash — tabiiy joylari. Partial — "qisman".

2.2 Required<T> — hamma maydon majburiy

Teskarisi: ixtiyoriy maydonlarni majburiy qiladi. Masalan, sozlamalar ixtiyoriy keladi, lekin standart qiymatlar qo'shilgach — hammasi bor bo'lishi kerak:

ts
type Settings = { tip?: number; currency?: string };
const full: Required<Settings> = { tip: 0.1 };

Kompilyator:

text
TS2741: Property 'currency' is missing in type '{ tip: number; }' but required in type 'Required<Settings>'.

Tarjimasi: "currency xususiyati { tip: number; } da yo'q, lekin Required<Settings> da majburiy". Required ? belgilarini olib tashladi — endi currency ham bo'lishi shart.

2.3 Readonly<T> — hamma maydon faqat o'qish uchun

ts
type Dish = { id: number; name: string; price: number };
const osh: Readonly<Dish> = { id: 1, name: "Osh", price: 35000 };
osh.price = 30000;

Kompilyator:

text
TS2540: Cannot assign to 'price' because it is a read-only property.

Tarjimasi: "price ga yozib bo'lmaydi, chunki u faqat o'qish uchun".

vazifalar dagi boshMatnlar: Readonly<Record<Filtr, string>> — ikkita utility ichma-ich (Index signature va Record darsida ko'rgandik). Readonly ham sayoz: ichki massiv va obyektlar o'zgaruvchan qoladi (Klasslar TypeScript'da darsidagi readonly kabi).

2.4 Pick<T, K> — faqat tanlangan maydonlar

ts
type Dish = {
  id: number;
  name: string;
  price: number;
  cookMinutes: number;
};
type DishRow = Pick<Dish, "name" | "price">;

const row: DishRow = { name: "Manti", price: 30000 };
console.log(row); // { name: 'Manti', price: 30000 }

Pick — "tanlab olish": K — kalitlar union'i. Ortiqcha maydon berilsa — odatdagi ortiqcha xususiyat tekshiruvi:

ts
type Dish = { id: number; name: string; price: number };
type DishRow = Pick<Dish, "name" | "price">;
const row: DishRow = { name: "Osh", price: 1, id: 1 };

Kompilyator:

text
TS2353: Object literal may only specify known properties, and 'id' does not exist in type 'DishRow'.

Tarjimasi: "Obyekt literalida faqat ma'lum xususiyatlar bo'lishi mumkin, id esa DishRow turida yo'q" — Pick uni olmagan edi.

2.5 Omit<T, K> — ko'rsatilganlardan tashqari hammasi

ts
type Dish = { id: number; name: string; price: number };
type NewDish = Omit<Dish, "id">;

const fresh: NewDish = { name: "Somsa", price: 8000 };
console.log(fresh.name); // Somsa

Omit — "tashlab ketish". Pick ga teskari: maydonlar ko'p, olib tashlanadigani oz bo'lsa — Omit qulayroq.

2.6 Record<K, V> — eslatma

Index signature va Record darsida to'liq ko'rgandik: Record<"osh" | "manti", number> — har kalitga qiymat. U ham utility type — shu oilaning a'zosi.

2.7 Utility'lar birga: maydon turini almashtirish

Kengaytirish va kesishma darsida bola tur ota maydonining turini o'zgartira olmasligini ko'rdik (TS2430). Va'da qilingan yechim — Omit va kesishma:

ts
type MenuItem = { name: string; price: number };
type PrintedItem = Omit<MenuItem, "price"> & { price: string };

function toPrinted(item: MenuItem): PrintedItem {
  return { ...item, price: `${item.price} so'm` };
}
const printed = toPrinted({ name: "Osh", price: 35000 });
console.log(printed.price); // 35000 so'm

Omit eski price ni olib tashladi, & yangisini qo'shdi. Natija: { name: string; price: string } — chek uchun narx satr ko'rinishida. Utility'lar shunday birlashadi: Partial<Pick<…>>, Readonly<Record<…>>, Omit<…> & {…}. Har biri bitta kichik o'zgarish qiladi, birga esa kerakli shaklni beradi.

Tekshirib ko'ring: type T = Partial<Pick<Dish, "name" | "price">> — T ga {} mos keladimi? { id: 1 } chi?

Javob

{} — mos: Pick ikki maydonni oldi, Partial ularni ixtiyoriy qildi. { id: 1 } — mos emas: id Pick da tanlanmagan, ortiqcha xususiyat tekshiruvi TS2353 beradi.

3. Omit tuzog'i: kalit tekshirilmaydi

Pick da noto'g'ri kalit yozib ko'ramiz:

ts
type Dish = { id: number; name: string; price: number };
type Row = Pick<Dish, "prise">;

Kompilyator:

text
TS2344: Type '"prise"' does not satisfy the constraint 'keyof Dish'.

Tarjimasi: ""prise" turi keyof Dish cheklovini qanoatlantirmaydi". Pick ning ta'rifida K extends keyof T bor (Generic cheklovlar) — xato kalit ushlandi. Endi Omit:

ts
type Dish = { id: number; name: string; price: number };
type NoPrice = Omit<Dish, "prise">;

const d: NoPrice = { id: 1, name: "Osh", price: 35000 };
console.log(d.price); // 35000

tsc — xatosiz! Kompilyator bu yozuvni shunday ochadi (Omit ning ichki ta'rifi «Ular qanday yozilgan» bo'limida):

Qadam Nima bo'ldi? Natija
1 keyof Dish "id" | "name" | "price"
2 Undan "prise" olib tashlandi — u yerda yo'q edi o'zgarmadi: "id" | "name" | "price"
3 Shu kalitlar tanlandi (Pick) { id: number; name: string; price: number }

Omit ning kalit parametri keyof T bilan emas, istalgan kalit bilan cheklangan. "prise" — Dish da yo'q kalit, uni "olib tashlash" hech narsa qilmadi va price joyida qoldi. Biz narxsiz tur yasadik deb o'ylaymiz, aslida esa u o'zgarmagan.

Qoida: Omit dan keyin natija turini hover'da bir marta tekshiring. Yoki muhim joylarda Pick ni afzal ko'ring — u kalitlarni tekshiradi.

4. Union'ni filtrlaydiganlar

4.1 Exclude va Extract

Bu ikkisi obyekt emas, union bilan ishlaydi:

ts
type Status = "yangi" | "tayyorlanmoqda" | "tayyor" | "bekor";
const active: Exclude<Status, "bekor"> = "bekor";
const done: Extract<Status, "tayyor" | "berildi"> = "yangi";

Kompilyator:

text
TS2322: Type '"bekor"' is not assignable to type '"tayyor" | "tayyorlanmoqda" | "yangi"'.
TS2322: Type '"yangi"' is not assignable to type '"tayyor"'.
  • Exclude<Status, "bekor"> — "Status dan "bekor" ni olib tashla": "yangi" | "tayyorlanmoqda" | "tayyor".
  • Extract<Status, "tayyor" | "berildi"> — "Status dan faqat ikkinchi union'da ham borlarini qoldir": "tayyor". "berildi" Status da yo'q — e'tiborsiz qoldi.

Tarjimasi: birinchisi — ""bekor" ni qolgan uch holat union'iga berib bo'lmaydi", ikkinchisi — ""yangi" ni "tayyor" ga berib bo'lmaydi". Farqni eslab qolish oson: Omit/Pick — obyekt maydonlari uchun, Exclude/Extract — union a'zolari uchun.

4.2 NonNullable<T> — null va undefined siz

ts
type MaybeName = string | null | undefined;
const name: NonNullable<MaybeName> = null;

Kompilyator:

text
TS2322: Type 'null' is not assignable to type 'string'.

Tarjimasi: "null ni string ga berib bo'lmaydi" — NonNullable dan keyin faqat string qoldi. NonNullable<string | null | undefined> — string. null va undefined darsidagi toraytirishning tur darajasidagi shakli. vazifalar ning api.ts ida aniq shunday qo'llanish bor — «Vazifalar qadami» mashqida ko'rasiz.

5. Funksiya va klassdan tur olish

5.1 ReturnType va Parameters

O'tgan darsda typeof fn funksiyaning to'liq imzosini berardi. Undan qismlarni olish:

ts
function makeOrder(table: number, dishes: string[]) {
  return { table, dishes, total: 0 };
}

type Order = ReturnType<typeof makeOrder>;
type OrderArgs = Parameters<typeof makeOrder>;

const args: OrderArgs = [7, ["Osh", "Ko'k choy"]];
const order: Order = makeOrder(...args);
console.log(order.table, order.dishes.length); // 7 2
  • ReturnType<typeof makeOrder> — { table: number; dishes: string[]; total: number }. Funksiya natija turi yozilmagan — TypeScript chiqargan, biz esa uni nom bilan oldik.
  • Parameters<typeof makeOrder> — [table: number, dishes: string[]] — parametrlar tuple'i.

Eng ko'p uchraydigan holat: kutubxona funksiya eksport qiladi, lekin uning natija turini eksport qilmaydi. ReturnType uni "qo'lga oladi".

5.2 Awaited — Promise ichidagi tur

async funksiyaning natijasi — Promise. Ichidagi turni olish:

ts
type Dish = { name: string; price: number };
async function loadMenu(): Promise<Dish[]> {
  return [];
}
const menu: Awaited<ReturnType<typeof loadMenu>> = 5;

Kompilyator:

text
TS2322: Type 'number' is not assignable to type 'Dish[]'.

Tarjimasi: "number ni Dish[] ga berib bo'lmaydi". Demak Awaited<ReturnType<…>> haqiqatan Dish[] bo'ldi. ReturnType<typeof loadMenu> — Promise<Dish[]>, Awaited<…> uni ochadi — Dish[]. await operatorining tur darajasidagi aksi.

5.3 InstanceType — klass nusxasining turi

ts
class Queue {
  items: string[] = [];
}
type QueueObject = InstanceType<typeof Queue>;
const q: QueueObject = 5;

Kompilyator:

text
TS2322: Type 'number' is not assignable to type 'Queue'.

Tarjimasi: "number ni Queue ga berib bo'lmaydi" — InstanceType natijasi klass nusxasining turi ekan. typeof Queue — klassning o'zi (konstruktor), InstanceType<…> — new dan chiqadigan nusxa. Odatda klass nomining o'zi (Queue) yetadi. InstanceType klass dinamik keladigan generic kodda kerak: function create<C extends new () => object>(cls: C): InstanceType<C>.

5.4 Hammasi bir jadvalda

Utility Nima qiladi Misol natija
Partial<T> / Required<T> hamma maydon ? / majburiy { price?: number }
Readonly<T> hamma maydon readonly { readonly price: number }
Pick<T, K> / Omit<T, K> maydonlarni tanlash / tashlash { name; price }
Record<K, V> kalitlarga qiymat { osh: number; … }
Exclude<U, X> / Extract<U, X> union a'zolarini olib tashlash / qoldirish "yangi" | "tayyor"
NonNullable<T> null/undefined siz string
ReturnType / Parameters funksiya natijasi / parametrlari { … } / [a, b]
Awaited<T> Promise ichidagi tur Dish[]
InstanceType<C> klass nusxasi turi Queue

5.5 Ular qanday yozilgan — bir nazar

Bularning hammasi sehr emas — TypeScript'ning lib.es5.d.ts faylida oddiy tur sifatida yozilgan. Masalan, Partial va Pick:

ts
type Partial<T> = {
    [P in keyof T]?: T[P];
};
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Hozir bu yozuvni to'liq tushunish shart emas. Lekin tanish qismlarni ko'ring: keyof T va T[P] — keyof va indexed access, K extends keyof T — generic cheklov. Shu cheklov tufayli Pick noto'g'ri kalitga TS2344 berdi. Omit esa shunday yozilgan: type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>> — keyof any "istalgan kalit" degani, shuning uchun u harf xatosini ko'rmaydi. [P in …] esa yangi: "har bir kalit bo'ylab aylanib, yangi maydon yasa". Bu — mapped type, uni Mapped types darsida o'rganasiz. Exclude, ReturnType esa conditional types bilan yozilgan (Conditional types). O'sha darslardan keyin bu jadvaldagi har bir utility'ni o'zingiz qayta yoza olasiz.

Tekshirib ko'ring: function getUser(id: number) { return { id, name: "Malika" }; } — getUser natijasi turini qanday olasiz? Uning name maydoni turi-chi?

Javob

ReturnType<typeof getUser> — { id: number; name: string }. name maydoni turi — ReturnType<typeof getUser>["name"], ya'ni string (indexed access utility natijasiga ham qo'llanadi).

Tekshirib ko'ring: type T = Exclude<"osh" | "manti" | "somsa", "somsa" | "lagmon"> — T qanday?

Javob

"osh" | "manti". "somsa" olib tashlandi, "lagmon" esa birinchi union'da yo'q edi — Exclude unga e'tibor bermaydi.

6. TypeScript ushlamaydigan tuzoq: Partial va spread

Partial — PATCH uchun qulay. Yangilashni spread bilan qo'llaymiz:

ts
type Dish = { name: string; price: number };

function update(dish: Dish, patch: Partial<Dish>): Dish {
  return { ...dish, ...patch };
}

const base = { name: "Osh", price: 35000 };
const osh = update(base, { price: undefined });
console.log(osh.price.toFixed(0));

tsc — xatosiz. Node esa:

text
TypeError: Cannot read properties of undefined (reading 'toFixed')

price?: number odatiy sozlamada "price yo'q yoki undefined" degani. { price: undefined } ruxsat etildi. Spread esa undefined ni ham yozadi — eski narx o'chdi. Funksiya natijasi Dish deb e'lon qilingan, lekin price — undefined.

Himoya — exactOptionalPropertyTypes bayrog'i: "ixtiyoriy maydon yo'q bo'lishi mumkin, lekin undefined ga teng bo'lishi mumkin emas":

ts
// @ts-options: {"exactOptionalPropertyTypes": true}
type Dish = { name: string; price: number };
function update(dish: Dish, patch: Partial<Dish>): Dish {
  return { ...dish, ...patch };
}
const base = { name: "Osh", price: 35000 };
const osh = update(base, { price: undefined });

Kompilyator:

text
TS2379: Argument of type '{ price: undefined; }' is not assignable to parameter of type 'Partial<Dish>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
  Types of property 'price' are incompatible.
    Type 'undefined' is not assignable to type 'number'.

Tarjimasi: "{ price: undefined; } argumentini exactOptionalPropertyTypes: true bo'lganda Partial<Dish> parametriga berib bo'lmaydi. undefined ni maqsad xususiyatlari turiga qo'shishni o'ylab ko'ring". Pastki qatorlar sababni aytadi: price ga undefined emas, faqat son yoki umuman yo'qligi mumkin. Bu bayroq strict ga kirmaydi. tsc --init (TypeScript 7) uni yoqadi, vazifalar esa Strict bayroqlar oilasi qadamida yoqadi. Serverdan kelgan PATCH tanasida esa bayroq ham yordam bermaydi — u ishlash paytida tekshiriladi.

7. Ko'p uchraydigan xatolar

7.1 Variant turlarni qo'lda nusxalash

NewDish, DishPatch — Dish dan ajralib qoladi. Tuzatish: Omit<Dish, "id">, Partial<Dish>.

7.2 Omit da harf xatosi

Omit<Dish, "prise"> — jim, hech narsa olib tashlanmaydi. Tuzatish: hover'da tekshiring yoki Pick ishlating.

7.3 Exclude ni obyektga qo'llash

Exclude<Dish, "id"> — maydonni olib tashlamaydi (Dish union emas). Tuzatish: obyekt maydonlari uchun Omit.

7.4 ReturnType<fn> (typeof siz)

ReturnType<makeOrder> — TS2749: 'makeOrder' refers to a value…. Tuzatish: ReturnType<typeof makeOrder>.

7.5 Partial + spread va undefined

Natija turi yolg'on gapiradi. Tuzatish: exactOptionalPropertyTypes yoki undefined qiymatlarni spread'dan oldin tozalash.

8. Mashqlar

1-mashq (oson): Utility'ni tanlang

ts
type Guest = { id: number; name: string; tel: string; vip: boolean };
type GuestForm = Omit<Guest, "id">;
type GuestCard = Pick<Guest, "name" | "vip">;
const card: GuestCard = { name: "Malika", vip: true };
console.log(Object.keys(card).length); // 2

GuestForm da nechta maydon bor: [:3]. Hamma maydoni ixtiyoriy Guest qaysi utility bilan yasaladi: [:Partial]. Exclude<"id" | "name", "id">: .

Yechim
  • 3 ta: name, tel, vip — id olib tashlandi.
  • Partial<Guest>.
  • "name": union'dan "id" olib tashlandi.

2-mashq (o'rta): Holatlar union'idan

ts
type Status =
  "yangi" | "tayyorlanmoqda" | "tayyor" | "berildi" | "bekor";

Uchta tur yasang, union'ni qayta yozmasdan: KitchenStatus — oshxona ekranida ko'rinadiganlar ("berildi" va "bekor" siz); FinalStatus — yakuniy holatlar ("berildi" va "bekor"); isFinal(s: Status): s is FinalStatus — tur predikati.

Yechim
ts
type Status =
  "yangi" | "tayyorlanmoqda" | "tayyor" | "berildi" | "bekor";
type FinalStatus = Extract<Status, "berildi" | "bekor">;
type KitchenStatus = Exclude<Status, FinalStatus>;

function isFinal(s: Status): s is FinalStatus {
  return s === "berildi" || s === "bekor";
}

const board: KitchenStatus[] = ["yangi", "tayyorlanmoqda", "tayyor"];
console.log(board.length); // 3
console.log(isFinal("berildi"), isFinal("tayyor")); // true false
  • KitchenStatus FinalStatus dan yasaldi — yakuniy holat qo'shilsa, ekran turidan o'zi chiqib ketadi.
  • isFinal — tur predikati: true shoxida s — FinalStatus, false shoxida — KitchenStatus.

3-mashq (qiyin): Buyurtma turlari bitta manbadan

Order turidan uchta tur va uchta funksiya yasang: NewOrder (yaratish — id va createdAt siz), OrderPatch (faqat table va items, ixtiyoriy), OrderSummary (id va total). createOrder(data), applyPatch(order, patch) (asl buyurtma o'zgarmasin), summarize(order). exactOptionalPropertyTypes yoqilgan bo'lsin.

Yechim
ts
// @ts-options: {"exactOptionalPropertyTypes": true}
type Order = {
  readonly id: number;
  table: number;
  items: string[];
  total: number;
  createdAt: string;
};

type NewOrder = Omit<Order, "id" | "createdAt">;
type OrderPatch = Partial<Pick<Order, "table" | "items">>;
type OrderSummary = Pick<Order, "id" | "total">;

let nextId = 100;

function createOrder(data: NewOrder): Order {
  return { ...data, id: nextId++, createdAt: "2026-10-06T12:00" };
}

function applyPatch(order: Order, patch: OrderPatch): Order {
  return { ...order, ...patch };
}

function summarize(order: Order): OrderSummary {
  return { id: order.id, total: order.total };
}

const o = createOrder({ table: 7, items: ["Osh"], total: 35000 });
const moved = applyPatch(o, { table: 3 });
console.log(summarize(moved), moved.table, o.table);

Konsolda:

text
{ id: 100, total: 35000 } 3 7
  • Partial<Pick<…>> — ikki utility ichma-ich: avval tanlash, keyin ixtiyoriy qilish.
  • applyPatch spread bilan yangi obyekt qaytaradi — o.table 7 qoldi. exactOptionalPropertyTypes tufayli { table: undefined } berib bo'lmaydi.
  • summarize — Order ga ortiqcha maydon qo'shilsa ham OrderSummary o'zgarmaydi: u faqat kerakli ikki maydonni oladi.

4-mashq: Vazifalar qadami — api.ts

api.js (11-qismdan beri — server bilan gaplashadigan yagona modul) .ts ga o'tadi. So'rov tanalari VazifaMalumoti dan utility types bilan yasaladi.

  • Branch: refactor/api-utility-types
  • Commit: refactor: api.ts — so'rov tanalari Pick/Partial/Omit bilan, tanasi: javobniOqi any → unknown; ApiKlient = ReturnType<typeof apiKlient>
  1. git mv assets/js/api.js assets/js/api.ts, npx tsc --noEmit — nechta xato?
  2. So'rov tanalari: YangiVazifa (POST — faqat matn) va VazifaOzgarishi (PATCH — id dan boshqa maydonlar, ixtiyoriy). Klient obyektining turi — ApiKlient (funksiyadan chiqarilsin).
  3. javobniOqi natijasi JSDoc'da any edi — unknown qiling. Xato xabarini o'qishdagi malumot?.xato — unknown bilan ishlamaydi; uni alohida funksiyaga oling.
  4. Import yo'llari (asosiy.js, api.test.js, api.tarmoq.js) va sw.js da VERSIYA = "v5-6".
Yechim

1. Nomi o'zgartirilganda — 33 ta xato:

api.js → api.ts: 33 xato kodlar bo'yicha
  • TS7006 (any parametr)24 xato
  • TS7031 (any destructuring)4 xato
  • TS2339 (yo'q xususiyat)3 xato
  • TS2739 (maydonlar yo'q)1 xato
  • TS7053 (any indeks)1 xato

Manba: O'lchandi: tsc 7.0.2 --noEmit, vazifalar holatlar/21 → api.ts, Node 24.21.0, 2026-10-06

Ikkitasi qiziq:

text
assets/js/api.ts(85,5): error TS7053: Element implicitly has an 'any' type because expression of type '"Content-Type"' can't be used to index type '{ Accept: string; }'.
  Property 'Content-Type' does not exist on type '{ Accept: string; }'.
assets/js/api.ts(126,33): error TS2739: Type '{}' is missing the following properties from type '{ kutish?: number | undefined; metod?: string | undefined; signal: any; tana: any; }': signal, tana

Birinchisi: headers: { Accept: "application/json" } dan TypeScript aniq bitta kalitli tur chiqardi, keyin headers["Content-Type"] = … — yo'q kalit. Tuzatish — sarlavhalar turini lug'at deb yozish: Record<string, string>. Ikkinchisi: JSDoc'dagi @typedef lar .ts da o'qilmadi, destructuring'dan chiqarilgan tur signal va tana ni majburiy deb oldi.

2–3. Utility types bilan — api.ts ning tur qismi:

ts
// Utility types: so'rov tanalari VazifaMalumoti'dan yasaladi — maydon
// nomi yoki turi o'zgarsa, bu yerlar ham tsc xatosi bilan eslatadi.
/** POST: yangi vazifa — faqat matn (id va holatni server beradi) */
export type YangiVazifa = Pick<VazifaMalumoti, "matn">;
/** PATCH: matn va/yoki bajarildi; id o'zgarmaydi */
export type VazifaOzgarishi = Partial<Omit<VazifaMalumoti, "id">>;

type IchkiSozlama = SorovSozlamasi & {
  metod?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE";
  tana?: unknown;
};

Mana bu turlar qanday yasalgani:

flowchart LR
  V["VazifaMalumoti<br/>id, matn, bajarildi"]
  V -- "Pick 'matn'" --> Y["YangiVazifa<br/>matn"]
  V -- "Omit 'id'" --> O["matn, bajarildi"]
  O -- "Partial" --> Z["VazifaOzgarishi<br/>matn?, bajarildi?"]

Bitta asosiy tur — ikkita so'rov tanasi. VazifaMalumoti ga maydon qo'shilsa, PATCH turi uni o'zi oladi.

Klient va yordamchilar:

ts
function yoz(
  yol: string,
  metod: NonNullable<IchkiSozlama["metod"]>,
  tana: unknown,
  sozlama?: SorovSozlamasi,
) { … }

/** Klient obyektining turi — funksiyadan chiqarib olinadi */
export type ApiKlient = ReturnType<typeof apiKlient>;
  • NonNullable<IchkiSozlama["metod"]> — indexed access ("GET" | … | undefined, chunki metod?: ixtiyoriy) va NonNullable (undefined olib tashlandi). Yozuv so'rovida metod har doim aniq.
  • ReturnType<typeof apiKlient> — apiKlient() qaytaradigan obyekt (royxat, qosh, yangila, ochir, almashtir) turini qo'lda yozmasdan oldik. Metod qo'shilsa, tur o'zi kengayadi.
  • Sarlavhalar: RequestInit & { headers: Record<string, string> } — fetch sozlamasi turi va kesishma bilan "sarlavhalar — lug'at".

javobniOqi — any o'rniga unknown:

ts
// Server xato javobida { xato: "..." } yuboradi
function serverXabari(malumot: unknown): string | undefined {
  if (
    typeof malumot === "object" &&
    malumot !== null &&
    "xato" in malumot &&
    typeof malumot.xato === "string"
  ) {
    return malumot.xato;
  }
  return undefined;
}

JavaScript versiyasida malumot?.xato tekshiruvsiz o'tardi. Masalan, server { "xato": 42 } yuborsa, xabar o'rniga son chiqardi. Endi esa toraytirish majburiy. Funksiya javobniOqi endi unknown qaytaradi va javob shaklini chaqiruvchi tekshiradi — bu API ma'lumotlarini tiplash qadamida to'liq qilinadi. Yana bir o'zgarish: tarmoqXatosi dagi /** @type {Error} */ (xato) assertion xato instanceof Error tekshiruviga almashdi.

Turlar haqiqatan ishlaydi — vaqtinchalik faylda tekshirildi (haqiqiy tsc):

text
error TS2353: Object literal may only specify known properties, and 'id' does not exist in type 'Partial<Omit<VazifaMalumoti, "id">>'.
error TS2322: Type 'string' is not assignable to type 'boolean | undefined'.

PATCH tanasiga id berib bo'lmaydi, bajarildi: "ha" (satr) ham o'tmaydi.

Commit va PR:

bash
git switch -c refactor/api-utility-types
git mv assets/js/api.js assets/js/api.ts
# turlar, unknown, import yo'llari, sw.js VERSIYA
npm run build && npm test && npm run tip
npm run lint && npm run format:check
git add .
git commit -m "refactor: api.ts — so'rov tanalari Pick/Partial/Omit bilan" \
  -m "javobniOqi any → unknown; ApiKlient = ReturnType<typeof apiKlient>"
git push -u origin refactor/api-utility-types
gh pr create --fill
gh pr merge --merge

Commit sarlavhasi — 60 belgi. Natija: npm test — 137/137, npm run test:tarmoq — 2/2 (haqiqiy API bilan), tip, lint, format:check — toza. Brauzer tekshiruvi (dist/) — 159/159. Diff: 6 fayl, +220 −211.

9. Real ishda

  • API qatlami — utility types'ning asosiy uyi: CreateUserDto = Omit<User, "id" | "createdAt">, UpdateUserDto = Partial<CreateUserDto>. NestJS (keyingi qismlarda) da PartialType, PickType kabi yordamchilar aynan shu g'oyani klasslar uchun bajaradi.
  • Forma holati: Partial<FormValues> — to'ldirilayotgan forma, Required<FormValues> — yuborishdan oldin tekshirilgan.
  • Kutubxona turlarini "qo'lga olish": ReturnType<typeof createStore>, Parameters<typeof fetch>[1] (fetch sozlamasi), Awaited<ReturnType<typeof loadUser>> — eksport qilinmagan turni olishning standart yo'li.
  • Intervyu: "Pick va Omit farqi?", "Exclude va Omit farqi?", "Partial ni o'zingiz yozing" (javobi — Mapped types darsida) — juda tez-tez beriladi.

Xulosa

  • Utility types — tayyor tur-funksiyalar: bitta asosiy tur, variantlari formula bilan (Omit<Dish, "id">, Partial<Dish>).
  • Obyekt maydonlari: Partial, Required, Readonly, Pick, Omit, Record. Union a'zolari: Exclude, Extract, NonNullable.
  • Funksiya va klassdan: ReturnType, Parameters, Awaited, InstanceType — typeof bilan.
  • Pick kalitlarni tekshiradi (TS2344), Omit — tekshirmaydi: noto'g'ri kalit jim o'tadi.
  • Partial + spread undefined ni yozib yuboradi — exactOptionalPropertyTypes buni ushlaydi.

Keyingi dars: Mapped types — { [K in keyof T]: … } bilan Partial va Readonly ni o'zingiz yozasiz, kalitlarni qayta nomlaysiz va filtrlaysiz.

Manbalar

  • TypeScript Handbook: "Utility Types" — typescriptlang.org/docs/handbook/utility-types.html
  • TSConfig: exactOptionalPropertyTypes — typescriptlang.org/tsconfig#exactOptionalPropertyTypes
  • TypeScript 4.5 Release Notes: "The Awaited Type" — typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
TypeScript utility types: Partial, Pick, Omit, ReturnType va boshqalar — IlmHamroh