Mundarija (30)
- Bu darsda
- 1. Nega bu kerak?
- 2. T extends …: generic'ga cheklov
- 2.1 Yozuv
- 2.2 Cheklovga mos kelmasa
- 2.3 Cheklov — interfeys yoki tur nomi
- 3. keyof: obyekt kalitlari union'i
- 3.1 Operator
- 3.2 getProperty: kalit va qiymat turi bog'langan
- 3.3 Cheklovsiz kalit — TS7053
- 4. Bir nechta tur parametri
- 4.1 Parametrlar bir-biriga tayanadi
- 4.2 Argumentlar ro'yxati — tur parametri
- 5. Tuzoq: cheklov — bu "kamida", "aynan" emas
- 5.1 T ni o'zingiz yasay olmaysiz
- 5.2 TypeScript ushlamaydigan tuzoq: keyof — kalitlarning hammasi emas
- 6. Ko'p uchraydigan xatolar
- 6.1 Cheklov o'rniga oddiy parametr turi
- 6.2 Kalitga string turi
- 6.3 T ni qo'lda yasash
- 6.4 Object.keys(x) as (keyof T)[]
- 6.5 Cheklovni haddan ziyod qattiq qo'yish
- 7. Mashqlar
- 1-mashq (oson): Natija turlari
- 2-mashq (o'rta): sumBy
- 3-mashq (qiyin): updateField — o'zgarmas yangilash
- 4-mashq: Vazifalar qadami — generic modullar .ts ga
- 8. Real ishda
- Xulosa
- Manbalar
TypeScript generic cheklovlar va keyof: T extends … va K extends keyof T
Qisqacha: Cheklov (constraint) generic'ga "kamida shu shaklda bo'lsin" talabini qo'yadi:
function longest<T extends { length: number }>(a: T, b: T): T. Endi ichkaridaa.lengthishlatish mumkin, natija esa baribir aniqT.keyof T—Tning kalitlari union'i,K extends keyof Tesa "faqat mavjud kalit" degani:getProperty(dish, "price")natijasi —number.
Bu darsda
T extends …bilan generic'ga cheklov qo'yasiz va nega u oddiy parametr turidan yaxshiroq ekanini ko'rsatasiz.keyofoperatori bilan obyekt kalitlarining union'ini olasiz.getProperty<T, K extends keyof T>vaT[K]natija turini yozasiz.- Bir nechta tur parametrini bir-biriga bog'laysiz.
vazifalardagiqidiruv,saralash,taymermodullarini generic cheklovlar bilan.tsga ko'chirasiz.
Oldin bilishingiz kerak: Generics: turni parametr qilish, Index signature va Record, Kengaytirish, kesishma va declaration merging, Strukturaviy tiplash.
1. Nega bu kerak?
O'tgan darsda cheklovsiz T "qora quti" ekanini ko'rdik: value.length — TS2339. Lekin ko'p funksiyalarga "istalgan tur" emas, "uzunligi bor istalgan tur" yoki "narxi bor istalgan obyekt" kerak.
Birinchi urinish — generic'siz, oddiy parametr turi bilan. Ikki matndan uzunrog'ini oladigan funksiya:
function longest(a: { length: number }, b: { length: number }) {
return a.length >= b.length ? a : b;
}
const title = longest("Osh", "Manti");
console.log(title.toUpperCase());Kompilyator:
TS2339: Property 'toUpperCase' does not exist on type '{ length: number; }'.Tarjimasi: "{ length: number; } turida toUpperCase xususiyati yo'q". Funksiya ishlaydi, lekin natija turi — { length: number }: "uzunligi bor nimadir". Biz satr berdik, lekin satr ekanini funksiya "unutdi". Bu Generics darsidagi unknown muammosining yarim versiyasi. Bizga ikkalasi kerak: ichkarida length ishlatish va natijada aniq tur.
2. T extends …: generic'ga cheklov
2.1 Yozuv
function longest<T extends { length: number }>(a: T, b: T): T {
return a.length >= b.length ? a : b;
}
const title = longest("Osh", "Manti");
const list = longest([35000], [28000, 30000]);
console.log(title.toUpperCase(), list.length); // MANTI 2T extends { length: number } — generic cheklov (generic constraint): "T istalgan tur bo'lishi mumkin, lekin unda length: number bo'lishi shart". Ikki natija:
- Ichkarida
a.length— ruxsat: TypeScriptTda kamidalengthborligini biladi. - Tashqarida
title—string,list—number[]. Aniq tur saqlandi.
Bu yerdagi extends — Kengaytirish darsidagi interface extends bilan bir xil ma'noda: "kamida shu maydonlar bor". Faqat endi u turga emas, tur parametriga qo'yilgan talab.
2.2 Cheklovga mos kelmasa
Talabni bajarmaydigan tur berilsa, chaqiruv xato beradi:
function lengthOf<T extends { length: number }>(value: T): number {
return value.length;
}
lengthOf(35000);Kompilyator:
TS2345: Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.Tarjimasi: "number turidagi argumentni { length: number; } turidagi parametrga berib bo'lmaydi". Sonda length yo'q. Xabar cheklovning o'zini ko'rsatadi — nima talab qilinganini darhol ko'rasiz.
Qaysi turlar o'tadi, qaysilari yo'q — rasmda:
flowchart LR
C{"T extends<br/>{ length: number }"}
S["string"] --> C
A["number[]"] --> C
O["{ length: 3, nomi: 'x' }"] --> C
N["number"] -.-> C
C --> OK["o'tadi: length bor"]
N -.-> X["TS2345: length yo'q"]Satr, massiv, length maydoni bor har qanday obyekt — o'tadi (Strukturaviy tiplash: shakl mos kelsa yetarli). Son — o'tmaydi.
2.3 Cheklov — interfeys yoki tur nomi
Cheklov sifatida tayyor tur nomini ham berish mumkin. «Bahor» menyusidan eng arzonini topamiz — taomlar ham, ichimliklar ham kelishi mumkin:
interface MenuItem {
name: string;
price: number;
}
function cheapest<T extends MenuItem>(
items: readonly T[],
): T | undefined {
let best: T | undefined;
for (const item of items) {
if (best === undefined || item.price < best.price) best = item;
}
return best;
}
const dishes = [
{ name: "Osh", price: 35000, cookMinutes: 40 },
{ name: "Lag'mon", price: 28000, cookMinutes: 25 },
];
const found = cheapest(dishes);
console.log(found?.name, found?.cookMinutes); // Lag'mon 25Asosiy nuqta — oxirgi qatorda. found?.cookMinutes ishladi, chunki natija turi MenuItem emas, aniq T — { name: string; price: number; cookMinutes: number }. Agar cheapest(items: readonly MenuItem[]): MenuItem deb yozganimizda, cookMinutes yo'qolib, TS2339 chiqardi. Cheklov ichkariga price ni beradi, generic esa tashqariga aniq turni qaytaradi.
vazifalar da aynan shu naqsh bor: tartibla<T extends VazifaMalumoti>(vazifalar: readonly T[], …): T[] — Vazifa klassi obyektlari kirsa, Vazifa[] chiqadi. Bu darsning «Vazifalar qadami» mashqida ko'ramiz.
Tekshirib ko'ring:
cheapest([{ name: "Choy" }])— nima bo'ladi?cheapest([{ name: "Choy", price: 5000, hot: true }])chi?
Javob
Birinchisi — TS2345: elementda price yo'q, cheklov MenuItem ni talab qiladi. Ikkinchisi — xatosiz: ortiqcha hot maydoni cheklovga xalaqit bermaydi, natija turi esa { name: string; price: number; hot: boolean } | undefined — hot saqlanadi.
3. keyof: obyekt kalitlari union'i
3.1 Operator
keyof — tur operatori: obyekt turining kalitlaridan literal union yasaydi.
type Dish = { name: string; price: number; cookMinutes: number };
type DishKey = keyof Dish;
const key: DishKey = "price";
console.log(key); // pricekeyof Dish — "name" | "price" | "cookMinutes". Hover'da ba'zan keyof Dish ko'rinishida qoladi — ma'nosi bir xil. Ro'yxatda bo'lmagan kalit — xato:
type Dish = { name: string; price: number; cookMinutes: number };
const key: keyof Dish = "narx";Kompilyator:
TS2322: Type '"narx"' is not assignable to type 'keyof Dish'.Tarjimasi: ""narx" turini keyof Dish turiga berib bo'lmaydi". Ya'ni: "Dish da bunday kalit yo'q". keyof ning qiymati shundaki, kalitlar ro'yxati qo'lda takrorlanmaydi. Dish ga yangi maydon qo'shilsa, keyof Dish ham o'zi kengayadi. enum va uning muqobillari darsidagi (typeof X)[keyof typeof X] qolipining o'rtadagi qismi — shu operator.
3.2 getProperty: kalit va qiymat turi bog'langan
Endi keyof ni generic bilan birlashtiramiz. Obyektdan kalit bo'yicha qiymat oladigan funksiya:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const osh = { name: "Osh", price: 35000, cookMinutes: 40 };
const price = getProperty(osh, "price");
const name = getProperty(osh, "name");
console.log(price + 5000, name.toUpperCase()); // 40000 OSHUch qismga ajratamiz:
<T, K extends keyof T>— ikkita tur parametri.T— obyekt turi.K— cheklangan: "Tning kalitlaridan biri".key: K— faqat mavjud kalit beriladi.: T[K]— indexed access (indeks bo'yicha tur): "TdagiKkalitining turi".K = "price"bo'lsa —number,K = "name"bo'lsa —string.
Hover'da price: number, name: string — har chaqiruvda kalitga mos aniq tur. getProperty(osh, "price") chaqiruvini kompilyator shunday yechadi:
| Qadam | Nima bo'ldi? | Natija |
|---|---|---|
| 1 | obj ga osh keldi |
T = { name: string; price: number; cookMinutes: number } |
| 2 | keyof T hisoblandi |
"name" | "price" | "cookMinutes" |
| 3 | key ga "price" keldi, ro'yxatda bor |
K = "price" |
| 4 | T[K] — T dagi price maydonining turi |
number |
"narx" berilsa, 3-qadamda to'xtaydi: u 2-qadamdagi ro'yxatda yo'q. T[K] yozuvini keyof, typeof va indexed access darsida to'liq o'rganamiz.
Noto'g'ri kalit — chaqiruvning o'zida xato:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
type Dish = { name: string; price: number };
const osh: Dish = { name: "Osh", price: 35000 };
getProperty(osh, "narx");Kompilyator:
TS2345: Argument of type '"narx"' is not assignable to parameter of type 'keyof Dish'.Tarjimasi: ""narx" turidagi argumentni keyof Dish turidagi parametrga berib bo'lmaydi". Muharrirda bu yanada qulay: getProperty(osh, " yozganingizda avtomatik to'ldirish faqat name va price ni taklif qiladi.
3.3 Cheklovsiz kalit — TS7053
K extends keyof T o'rniga oddiy string yozsak-chi?
function getAny<T>(obj: T, key: string) {
return obj[key];
}Kompilyator:
TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'unknown'.
No index signature with a parameter of type 'string' was found on type 'unknown'.Tarjimasi: "string turidagi ifoda bilan unknown ga indeks berib bo'lmaydi, shuning uchun element yashirincha any bo'ldi". Bu Index signature va Record darsidagi TS7053 ning o'zi: istalgan satr bilan indeks berib bo'lmaydi. Cheklovsiz T ning o'zi ham unknown deb ko'rildi. K extends keyof T ikkala muammoni birdan hal qiladi.
Tekshirib ko'ring:
type Guest = { name: string; phone?: string }uchungetProperty(guest, "phone")natijasining turi qanday?
Javob
string | undefined. T[K] maydonning to'liq turini oladi — ixtiyoriy maydonda u undefined ni ham o'z ichiga oladi. Shuning uchun natijani ishlatishdan oldin tekshirish kerak (null va undefined).
4. Bir nechta tur parametri
4.1 Parametrlar bir-biriga tayanadi
getProperty da K ning cheklovi T ga bog'liq edi. Shu usul bilan ro'yxatdan bitta maydonni yig'adigan funksiya:
function pluck<T, K extends keyof T>(
items: readonly T[],
key: K,
): T[K][] {
return items.map((item) => item[key]);
}
const menu = [
{ name: "Osh", price: 35000 },
{ name: "Manti", price: 30000 },
];
console.log(pluck(menu, "name")); // [ 'Osh', 'Manti' ]
console.log(pluck(menu, "price")); // [ 35000, 30000 ]pluck(menu, "name") — string[], pluck(menu, "price") — number[]. Natija turi kalitga qarab o'zgaradi. T[K][] ni o'ngdan chapga o'qing: "T dagi K maydon turining massivi".
Tekshirib ko'ring:
pluck(menu, "name")vamenu.map((d) => d.name)— natija turlari farq qiladimi? Undaplucknimaga kerak?
Javob
Farq qilmaydi — ikkalasi ham string[]. Funksiyaning foydasi boshqa: kalit qiymat sifatida uzatiladi. Uni foydalanuvchi tanlagan ustun nomidan, sozlamadan yoki boshqa funksiyadan olish mumkin. Cheklov (K extends keyof T) esa bunday dinamik kalit ham faqat mavjud maydon bo'lishini kafolatlaydi.
O'tgan darsdagi pair<T>(a: T, b: T) ikki xil turni qabul qilmasdi. Ikkita mustaqil tur parametri bilan bunday cheklov yo'q:
function merge<A extends object, B extends object>(
a: A,
b: B,
): A & B {
return { ...a, ...b };
}
const base = { name: "Osh", price: 35000 };
const dish = merge(base, { cookMinutes: 40 });
console.log(dish.name, dish.cookMinutes); // Osh 40A va B alohida chiqariladi, natija esa ularning kesishmasi: A & B. extends object — "faqat obyektlar" (son yoki satr emas), spread obyekt bilan ishlashi uchun.
4.2 Argumentlar ro'yxati — tur parametri
Yana bir kuchli naqsh: funksiyaning butun argumentlar ro'yxatini tur parametri qilish. Masalan, berilgan funksiyani ikki marta chaqiradigan yordamchi:
function callTwice<A extends unknown[]>(
fn: (...args: A) => void,
...args: A
): void {
fn(...args);
fn(...args);
}
callTwice((dish: string, qty: number) => {
console.log(`${dish} × ${qty}`);
}, "Osh", 2);Konsolda:
Osh × 2
Osh × 2A extends unknown[] — "A — qandaydir massiv (tuple)". fn ning parametrlaridan A = [dish: string, qty: number] chiqarildi. Endi ...args ham aynan shu tuple: "Osh", 2 dan boshqa narsa o'tmaydi:
function callTwice<A extends unknown[]>(
fn: (...args: A) => void,
...args: A
): void {
fn(...args);
}
callTwice((dish: string, qty: number) => {
console.log(dish, qty);
}, "Osh", "2");Kompilyator:
TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.Tarjimasi: "string turidagi argumentni number turidagi parametrga berib bo'lmaydi". A tuple'ida ikkinchi o'rin — qty: number, biz esa "2" satrini berdik. vazifalar dagi kechiktir (debounce, 12-qismdan) aynan shu naqsh bilan yozilgan: kechiktirilgan funksiya asl funksiyaning argumentlarini aynan qabul qiladi.
5. Tuzoq: cheklov — bu "kamida", "aynan" emas
5.1 T ni o'zingiz yasay olmaysiz
Cheklovli T dan qiymat qaytaradigan funksiya yangi obyekt yasab qaytarmoqchi:
function withDefaultName<T extends { name: string }>(item: T): T {
return { name: "Nomsiz" };
}Kompilyator:
TS2322: Type '{ name: string; }' is not assignable to type 'T'.
'{ name: string; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ name: string; }'.Tarjimasi: "{ name: string; } T ning cheklovga mos keladi, lekin T cheklovning boshqa kichik turi bilan to'ldirilishi mumkin". Oddiyroq: T — "kamida name bor narsa", lekin aniq nima ekanini chaqiruvchi hal qiladi. withDefaultName({ name: "Osh", price: 35000 }) chaqirilsa, T da price ham bor — { name: "Nomsiz" } esa unda yo'q. Funksiya T va'da berib, boshqa narsa qaytarardi.
Bu generic'lardagi eng ko'p uchraydigan xabarlardan biri. Tuzatish — T ni kiruvchi qiymatdan yasash: return { ...item, name: item.name || "Nomsiz" }; — bu T ning hamma maydonini saqlaydi.
5.2 TypeScript ushlamaydigan tuzoq: keyof — kalitlarning hammasi emas
keyof T — T turida e'lon qilingan kalitlar. Ishlash paytidagi obyektda esa ko'proq kalit bo'lishi mumkin (Strukturaviy tiplash). Index signature va Record darsida Object.keys nega string[] qaytarishini ko'rgandik. Agar buni as bilan "tuzatsak":
type Prices = { osh: number; manti: number };
function printAll(p: Prices): void {
for (const k of Object.keys(p) as (keyof Prices)[]) {
console.log(k, p[k].toFixed(0));
}
}
const fromMenu = { osh: 35000, manti: 30000, note: "yangi" };
printAll(fromMenu);Konsolda:
osh 35000
manti 30000
TypeError: p[k].toFixed is not a functiontsc — xatosiz: fromMenu da osh va manti bor, ortiqcha note ga ruxsat. as (keyof Prices)[] esa "kalitlar faqat shu ikkita" deb yolg'on va'da berdi. Uchinchi aylanishda k = "note", p[k] — "yangi" satri, unda toFixed yo'q. Qoida: Object.keys(…) as (keyof T)[] — as ning odatdagi xavfi (Type assertion). Kalitlar ro'yxatini aniq yozing (["osh", "manti"] as const) yoki har qiymatni tekshiring.
6. Ko'p uchraydigan xatolar
6.1 Cheklov o'rniga oddiy parametr turi
longest(a: { length: number }, …) — natija aniq turni yo'qotadi. Tuzatish: longest<T extends { length: number }>(a: T, b: T): T.
6.2 Kalitga string turi
(obj: T, key: string) => obj[key] — TS7053. Tuzatish: <T, K extends keyof T>(obj: T, key: K): T[K].
6.3 T ni qo'lda yasash
return { name: "…" } (T kutilganda) — TS2322 … could be instantiated with a different subtype. Tuzatish: natijani kiruvchi qiymatdan spread bilan yasang yoki natija turini cheklovning o'zi qiling.
6.4 Object.keys(x) as (keyof T)[]
Ortiqcha kalitlar ham keladi. Tuzatish: aniq kalitlar ro'yxati yoki tekshiruv.
6.5 Cheklovni haddan ziyod qattiq qo'yish
<T extends { name: string; price: number; cookMinutes: number }> — funksiyaga faqat price kerak bo'lsa ham, ichimliklar o'tmay qoladi. Tuzatish: cheklovda faqat funksiya haqiqatan ishlatadigan maydonlar.
7. Mashqlar
1-mashq (oson): Natija turlari
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const table = { no: 7, waiter: "Sardor", vip: false };
const a = getProperty(table, "waiter");
const b = getProperty(table, "vip");
console.log(a, b); // Sardor falsea ning turi: [:string]. b ning turi: [:boolean]. keyof typeof table da nechta a'zo bor: .
Yechim
a—string:T[K],K = "waiter".b—boolean:K = "vip".constbo'lsa ham obyekt maydonlari kengaygan (Tur chiqarish), shuning uchunfalseemas,boolean.- 3 ta:
"no" | "waiter" | "vip".
2-mashq (o'rta): sumBy
Ro'yxatdagi obyektlarning sonli maydonini yig'adigan funksiya yozing: sumBy(menu, "price"). Maydon soni bo'lmasa (sumBy(menu, "name")), tsc to'xtatsin. Ishora: elementga cheklov qo'ying — T extends Record<K, number>: "K kalitida son bor obyekt" (Index signature va Record). K — string.
Yechim
function sumBy<K extends string, T extends Record<K, number>>(
items: readonly T[],
key: K,
): number {
let sum = 0;
for (const item of items) sum += item[key];
return sum;
}
const order = [
{ name: "Osh", price: 35000, qty: 2 },
{ name: "Ko'k choy", price: 5000, qty: 1 },
];
console.log(sumBy(order, "price"), sumBy(order, "qty")); // 40000 3- Cheklovlar tartibi muhim:
Tning chekloviKga tayanadi, shuning uchunKbirinchi e'lon qilingan. item[key]—number:Record<K, number>shuni kafolatlaydi.sumBy(order, "name")—TS2345:namesatr,Record<"name", number>talabi bajarilmadi.
3-mashq (qiyin): updateField — o'zgarmas yangilash
Bron obyektining bitta maydonini yangi obyekt bilan almashtiradigan funksiya yozing: updateField(booking, "time", "20:00"). Asl obyekt o'zgarmasin. Talablar: kalit — faqat mavjud maydon; qiymat turi — shu maydon turi (people ga satr berib bo'lmasin).
Yechim
function updateField<T extends object, K extends keyof T>(
obj: T,
key: K,
value: T[K],
): T {
return { ...obj, [key]: value };
}
type Booking = { guest: string; people: number; time: string };
const b: Booking = { guest: "Dilshod aka", people: 4, time: "19:00" };
const moved = updateField(b, "time", "20:00");
console.log(moved.time, b.time); // 20:00 19:00Ikki noto'g'ri chaqiruv tsc da shunday to'xtaydi:
function updateField<T extends object, K extends keyof T>(
obj: T,
key: K,
value: T[K],
): T {
return { ...obj, [key]: value };
}
type Booking = { guest: string; people: number; time: string };
const b: Booking = { guest: "Dilshod aka", people: 4, time: "19:00" };
updateField(b, "people", "5");
updateField(b, "table", 7);Xato:
TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
TS2345: Argument of type '"table"' is not assignable to parameter of type 'keyof Booking'.value: T[K]— qiymat turi kalitga bog'langan:K = "people"bo'lsa,number.{ ...obj, [key]: value }— spread va hisoblangan kalit: nusxa, bitta maydon almashgan.b.timeo'zgarmadi.- Bu React holatini yangilashdagi naqshning o'zi (
setState({ ...state, time })) — 17-qismda qayta uchratasiz.
4-mashq: Vazifalar qadami — generic modullar .ts ga
vazifalar dagi uch "sof" modulda (DOM'siz) 12-qismdan beri JSDoc @template bor: qidir (qidiruv), tartibla (saralash), kechiktir (debounce). Ular — generic cheklovlarning tayyor misoli. Endi .ts ga o'tadi.
- Branch:
refactor/generics - Commit:
refactor: qidiruv, saralash, taymer — generic cheklovlar bilan .ts, tanasi:@template o'rniga <T extends …>; Oraliq — nomlangan tuple
git mvbilanqidiruv.js,saralash.js,taymer.js→.ts.npx tsc --noEmit— nechta xato?@templatelarni TypeScript cheklovlariga o'tkazing:qidir<T extends { readonly matn: string }>(vazifalar: readonly T[], sorov: string): T[]tartibla<T extends VazifaMalumoti>(vazifalar: readonly T[], saralash: Saralash): T[]kechiktir<A extends unknown[]>(ishlovchi: (...argumentlar: A) => void, kutish: number)
- Import yo'llari (
asosiy.js,holat.ts,marshrut.ts,render.js,royxat.ts, 3 ta test) vasw.jsdaVERSIYA = "v5-5". - Tajriba:
qidirni generic'siz yozib ko'ring —{ readonly matn: string }[]qabul qilib, shuni qaytarsin.tscnima deydi?
Yechim
1. Nomi o'zgartirilganda — 34 ta xato:
- TS7006 (any parametr)24 xato
- TS7005 (any o'zgaruvchi)5 xato
- TS7034 (any joylarda)2 xato
- TS7019 (any[] rest)1 xato
- TS7031 (any destructuring)1 xato
- TS23221 xato
Manba: O'lchandi: tsc 7.0.2 --noEmit, vazifalar holatlar/18 → qidiruv/saralash/taymer .ts, Node 24.21.0, 2026-10-06
Ko'pi — yashirin any: JSDoc turlari .ts da o'qilmaydi (Klasslar TypeScript'da qadamidagi kabi). taymer.ts dagilar yangi xil:
assets/js/taymer.ts(13,7): error TS7034: Variable 'taymer' implicitly has type 'any' in some locations where its type cannot be determined.
assets/js/taymer.ts(35,27): error TS7019: Rest parameter 'argumentlar' implicitly has an 'any[]' type.let taymer; — qiymatsiz e'lon, JSDoc turi esa e'tiborsiz. ...argumentlar — rest parametr, turi any[].
2. Generic cheklovlar bilan — taymer.ts:
// taymer.ts — tez-tez keladigan chaqiruvlarni kamaytirish
// (kanondagi JSDoc izohlari qisqartirildi)
export type Kechiktirilgan<A extends unknown[]> = ((
...argumentlar: A
) => void) & {
hoziroq(): void; // kutayotgan chaqiruvni hoziroq bajaradi
bekor(): void; // kutayotgan chaqiruvni tashlab yuboradi
};
export function kechiktir<A extends unknown[]>(
ishlovchi: (...argumentlar: A) => void,
kutish: number,
): Kechiktirilgan<A> {
let taymer: ReturnType<typeof setTimeout> | undefined;
// kutayotgan chaqiruv argumentlari
let kutayotgan: A | null = null;
function hoziroq(): void {
clearTimeout(taymer);
if (kutayotgan === null) {
return;
}
const argumentlar = kutayotgan;
kutayotgan = null;
ishlovchi(...argumentlar);
}
function bekor(): void {
clearTimeout(taymer);
kutayotgan = null;
}
function kechiktirilgan(...argumentlar: A): void {
kutayotgan = argumentlar;
clearTimeout(taymer);
taymer = setTimeout(hoziroq, kutish);
}
return Object.assign(kechiktirilgan, { hoziroq, bekor });
}A extends unknown[]— «Argumentlar ro'yxati — tur parametri» bo'limidagicallTwicenaqshi. Qidiruv maydonidagikechiktir((matn: string) => …, 300)danA = [matn: string]chiqariladi.Kechiktirilgan<A>— generic tur (typeham tur parametri oladi — Generic interface, type va klass darsida). U kesishma: "shu argumentli funksiya vahoziroq,bekormetodlari".ReturnType<typeof setTimeout>— "setTimeoutqaytaradigan tur": brauzerda son, Node'da obyekt. Tayyor yordamchi tur — Utility types darsida.
qidiruv.ts dagi qidir:
export function qidir<T extends { readonly matn: string }>(
vazifalar: readonly T[],
sorov: string,
): T[] {
const toza = normalla(sorov);
if (toza === "") {
return [...vazifalar];
}
return vazifalar.filter((v) => normalla(v.matn).includes(toza));
}Cheklovda faqat matn — funksiya boshqa maydonni ishlatmaydi («Cheklovni haddan ziyod qattiq qo'yish» qoidasi). Shu faylda Massiv va tuple turlari darsida ko'rgan export type Oraliq = [boshi: number, oxiri: number]; ham paydo bo'ldi.
4. Generic nega kerak — qidir generic'siz bo'lsa (haqiqiy tsc chiqishi):
assets/js/holat.ts(67,3): error TS2322: Type '{ readonly matn: string; }[]' is not assignable to type 'Vazifa[]'.
Type '{ readonly matn: string; }' is missing the following properties from type 'Vazifa': id, bajarildi, #matn, matnniOzgartir, and 2 more.«Nega bu kerak?» bo'limidagi longest holatining o'zi, endi haqiqiy loyihada. holat.ts dagi korinadiganlar(): Vazifa[] qidir natijasini qaytaradi. Generic'siz natija "matni bor nimadir" bo'lib qoldi — id, bajarildi, metodlar yo'qoldi.
saralash.ts da yana bir nozik joy bor: type Taqqoslovchi = (a: VazifaMalumoti, b: VazifaMalumoti) => number. Vazifa klassi obyektlari ham unga mos, chunki ularda id, matn (getter) va bajarildi bor — Strukturaviy tiplash. Klassni import qilish shart emas.
Commit va PR:
git switch -c refactor/generics
git mv assets/js/qidiruv.js assets/js/qidiruv.ts
git mv assets/js/saralash.js assets/js/saralash.ts
git mv assets/js/taymer.js assets/js/taymer.ts
# cheklovlar, 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: qidiruv, saralash, taymer — generic cheklovlar bilan .ts" \
-m "@template o'rniga <T extends …>; Oraliq — nomlangan tuple"
git push -u origin refactor/generics
gh pr create --fill
gh pr merge --mergeCommit sarlavhasi — 68 belgi. Natija: npm test — 137/137, tip, lint, format:check — toza. Brauzer tekshiruvi (dist/) — 159/159. Diff: 13 fayl, +101 −110.
8. Real ishda
- Kutubxona API'lari cheklovlarga to'la:
useState<S>, ORM'lardafindOne<T extends Entity>, lodash'dapick<T, K extends keyof T>.K extends keyof Tnaqshini hujjatlarda har kuni ko'rasiz. - Forma va jadval komponentlari:
<Table<Row> columns={…} />da ustun kalitikeyof Row— noto'g'ri ustun nomi yozish paytida ushlanadi. - Debounce, throttle, memoize —
A extends unknown[]naqshi: o'ralgan funksiya aslining argumentlarini saqlaydi. - Intervyu: "
T extendsnima qiladi?", "getProperty<T, K extends keyof T>yozing", "could be instantiated with a different subtypenimani anglatadi?" — middle darajadagi klassik savollar.
Xulosa
T extends Shakl— generic'ga "kamida shu shakl" talabi: ichkaridaShaklmaydonlari ishlatiladi, tashqarida aniqTqaytadi.keyof T— kalitlar union'i.K extends keyof T— faqat mavjud kalit,T[K]— shu kalitning turi.- Bir nechta tur parametri bir-biriga tayanishi mumkin (
K extends keyof T,T extends Record<K, number>). A extends unknown[]— argumentlar ro'yxatini (tuple) tur parametri qilish.- Cheklov — "kamida", "aynan" emas:
Tni qo'lda yasab bo'lmaydi (TS2322 … different subtype),keyof Tesa ishlash paytidagi hamma kalitlar emas.
Keyingi dars: Generic interface, type va klass — ApiResponse<T>, generic konteyner klass va standart tur parametri.
Manbalar
- TypeScript Handbook: "Generics" (Generic Constraints, Using Type Parameters in Generic Constraints) — typescriptlang.org/docs/handbook/2/generics.html#generic-constraints
- TypeScript Handbook: "Keyof Type Operator" — typescriptlang.org/docs/handbook/2/keyof-types.html
- TypeScript Handbook: "Indexed Access Types" — typescriptlang.org/docs/handbook/2/indexed-access-types.html
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!