TypeScript generiklar (generics) asoslari
Massivdan birinchi elementni qaytaradigan funksiya kerak. Uni matnlar uchun yozdingiz. Endi sonlar uchun ham kerak bo’ldi — yana bir xil funksiya yozasizmi?
Yoki any ishlatasizmi? Unda oldingi darsdagi
muammo qaytadi: natija tipi yo’qoladi.
Uchinchi yo’l bor — generik.
Muammoni ko’rsatamiz
any bilan yozilgan variant:
function firstItemAny(items: any[]): any {
return items[0];
}
const city = firstItemAny(["Toshkent"]);
console.log(city.toFixed(2));
Bu kod kompilyatsiyadan o’tadi. Matnda toFixed yo’q, lekin
TypeScript jim turadi — chunki any tekshiruvni o’chirdi.
Funksiya matn massivini oldi, lekin natija tipi haqidagi ma’lumot yo’qoldi.
Generic — tipni parametr sifatida uzatish
function firstItem<T>(items: T[]): T | undefined {
return items[0];
}
const firstCity = firstItem(["Toshkent", "Samarqand"]);
const firstScore = firstItem([90, 85]);
console.log(firstCity, firstScore);
Toshkent 90
Endi TypeScript tipni saqlab qoldi: firstCity — string,
firstScore — number. Buni tekshirib ko’ring:
const bad: number = firstItem(["Aziz"]);
example.ts(4,7): error TS2322: Type 'string | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
T — shunchaki nom, Type so’zining qisqartmasi. Uni istalgan nom
bilan almashtirish mumkin, lekin T keng tarqalgan kelishuv.
Tip qanday aniqlanadi
Ko’p holda tipni yozish shart emas — TypeScript uni argumentdan oladi:
// T avtomatik string bo'ldi
const name = firstItem(["Aziz"]);
Ba’zan uni aniq ko’rsatish kerak bo’ladi, masalan massiv bo’sh bo’lsa:
console.log(firstItem<number>([]));
undefined
Bo’sh massivdan TypeScript hech narsa aniqlay olmaydi, shuning uchun
<number> qo’lda yoziladi.
extends bilan cheklash
Ba’zan generik tip haqida biror narsa bilish kerak bo’ladi. Masalan
funksiya name maydoniga murojaat qiladi:
function longestName<T extends { name: string }>(items: T[]): string {
let longest = "";
for (const item of items) {
if (item.name.length > longest.length) {
longest = item.name;
}
}
return longest;
}
console.log(longestName([{ name: "Aziz" }, { name: "Malika" }]));
Malika
T extends { name: string } — “T har qanday tip bo’lishi mumkin,
lekin unda name maydoni bo’lishi shart” degani.
Shart bajarilmasa, xato chiqadi:
console.log(longestName([{ title: "Kitob" }]));
example.ts(4,28): error TS2353: Object literal may only specify known properties, and 'title' does not exist in type '{ name: string; }'.
Cheklashsiz item.name yozib bo’lmaydi: TypeScript T da bunday
maydon borligini bilmaydi.
Generic tip taxallusi
Generik faqat funksiyada emas, tip e’lonida ham ishlatiladi. Eng ko’p uchraydigan misol — server javobi:
type ApiResponse<T> = {
data: T;
success: boolean;
};
type User = { id: number; name: string };
const userResponse: ApiResponse<User> = {
data: { id: 1, name: "Aziz" },
success: true,
};
const listResponse: ApiResponse<string[]> = {
data: ["a", "b"],
success: true,
};
console.log(userResponse.data.name);
console.log(listResponse.data.length);
Aziz
2
Bitta shakl, turli ichki tiplar. success maydoni har javobda bir xil,
data esa har safar boshqacha.
Bu naqsh fetch bilan ishlaganda juda qo’l keladi: server javobining tashqi qobig’i doim bir xil bo’ladi.
Generic sinf
class Box<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
getAll(): T[] {
return this.items;
}
}
const numberBox = new Box<number>();
numberBox.add(10);
numberBox.add(20);
console.log(numberBox.getAll());
[ 10, 20 ]
numberBox.add("matn") yozsangiz xato chiqadi: quti sonlar uchun
yaratilgan. Klasslar darsidagi sinf shu tarzda
tip bilan himoyalanadi.
Siz generiklarni allaqachon ishlatgansiz
Array<string> yozuvini
massiv va kortej darsida ko’rgansiz —
bu generik edi. Promise<string> ham shunday: “matn bilan tugaydigan
va’da”.
async function loadName(): Promise<string> {
return "Aziz";
}
loadName().then((name) => console.log(name.toUpperCase()));
AZIZ
Promise<string> tufayli .then ichidagi name avtomatik string
bo’ladi. Promise darsidagi kod TypeScript’da shu
tarzda tekshiriladi.
Qachon generik yozish kerak
| Holat | Yechim |
|---|---|
| Funksiya bir nechta tip bilan ishlaydi va tipni saqlashi kerak | Generik |
| Tip noma’lum va ishlatilmaydi | unknown |
| Tip aniq bitta | Oddiy tip yozing |
Amaliy mashq
firstItem<T>funksiyasini yozib, uni matn va son massivlari bilan chaqiring;- Natijani noto’g’ri tipdagi o’zgaruvchiga berib,
TS2322xatosini o’qing; - Bo’sh massiv bilan chaqirib, tipni
<number>shaklida qo’lda ko’rsating; lastItem<T>funksiyasini o’zingiz yozing — qaytish tipidaundefinedni unutmang;T extends { id: number }cheklovli funksiya yozib,idsiz obyekt berib ko’ring;ApiResponse<T>tipini e’lon qilib, uni ikki xil ichki tip bilan ishlating.
4-qadam eng muhimi: qaytish tipiga undefined qo’shishni unutish
generik yozishdagi eng tipik xato.
Qisqacha xulosa
- Generik tipni parametr sifatida qabul qiladi va uni chiqishda saqlaydi.
anydan farqi shu:anytipni yo’qotadi, generik uni olib o’tadi.- Tip odatda argumentdan avtomatik aniqlanadi; kerak bo’lsa
<number>shaklida qo’lda beriladi. extendsgenerik tipga talab qo’yadi va funksiya ichida maydonlarga murojaat qilishga ruxsat beradi.- Generik tip taxallusi (
ApiResponse<T>) bitta shaklni turli ichki tiplar bilan ishlatadi. - Tip parametri bir marta ishlatilsa, generik ortiqcha —
unknownyetarli.
Keyingi darsda utility tiplar —
Partial, Pick, Omit va Record.