6 β Funksiya tiplari¶
β¬ οΈ Oldingi: 05 β Object tiplari va interface Β· π README Β· Keyingi: 07 β Union va literal tiplar β‘οΈ
Bu bobda: funksiyalarni tiplashni o'rganamiz β parametr va return annotation, return tipini TS o'zi qanday topishi (inference),
voidva undefined farqi, optional?, default qiymat va rest...args, funksiyaning o'zini bitta tip sifatida yozish ((a: number) => string), callback va yuqori tartibli funksiyalarni (HOF) tiplash, bitta nomga bir nechta imzo beruvchi overload'lar vathisparametri. Funksiya β har bir dasturning yuragi; uni to'g'ri tiplasangiz, butun loyiha mustahkam bo'ladi.
Muammo¶
JavaScript'da quyidagi funksiyani yozdingiz va hammasi joyida ko'rinadi:
Ertasiga hamkasbingiz uni shunday chaqiradi:
chegirma("50000", 10); // natija: "50000" - 5000 = ?
chegirma(50000); // foiz = undefined
chegirma(50000, 10, true); // ortiqcha argument β JS uni shunchaki tashlab yuboradi
Birinchi qatorda "50000" β matn (string), son emas. JavaScript hech narsa demaydi, ammo "50000" - 5000 hisoblanganda allaqachon kech: kassada noto'g'ri summa chiqadi. Ikkinchi qatorda foiz umuman berilmagan β undefined, va narx * undefined natijasi NaN ("Not a Number"). Uchinchi qatorda ortiqcha argument bor, lekin JS uni jimgina yutib yuboradi.
Muammoning ildizi bitta: funksiya nimani qabul qilishi va nimani qaytarishi hech qayerda yozilmagan. Funksiya β bu kirish (parametrlar) va chiqish (return qiymati) o'rtasidagi shartnoma. JS'da bu shartnoma faqat sizning kallangizda yoki sharhlarda yashaydi. TypeScript esa uni kodning o'ziga yozib qo'yadi va har chaqirishda tekshiradi:
function chegirma(narx: number, foiz: number): number {
return narx - (narx * foiz) / 100;
}
chegirma("50000", 10); // β Xato: Argument of type 'string' is not assignable to parameter of type 'number'.
chegirma(50000); // β Xato: Expected 2 arguments, but got 1.
Endi xatolar kodni yozish vaqtida β kassaga yetib bormasdan oldin β ko'rinadi. Bu bobda funksiyalarni shunday tiplashni boshdan oxir o'rganamiz.
JavaScript funksiyalari (parametr, return, callback, arrow funksiya, rest) bo'yicha asoslarni unutgan bo'lsangiz, JavaScript kitobiga qaytib o'ting. Bu yerda biz faqat tip qatlamiga e'tibor beramiz.
Parametr va return annotation¶
Funksiyani tiplashning ikki joyi bor: har bir parametrdan keyin va qavslardan keyin (return tipi).
O'qilishi: "qosh funksiyasi ikki number qabul qiladi va bitta number qaytaradi". Bu β yuqorida aytgan shartnomamiz, endi kodga yozilgan.
Annotation (tip belgilash) funksiyani ikki tomondan himoyalaydi:
- Chaqiruvchini himoyalaydi: noto'g'ri argument bersa, xato chiqadi.
- Funksiya ichini himoyalaydi: agar
returnqatoridanumbero'rniga boshqa narsa qaytarmoqchi bo'lsangiz, compiler ushlaydi.
function qosh(a: number, b: number): number {
return a + b;
}
qosh(2, "3"); // β Xato: Argument of type 'string' is not assignable to parameter of type 'number'.
π Return tipini yozib qo'yish β funksiya niyatini muhrlaydi. Quyidagi funksiya number qaytarishga va'da bergan, lekin tanasida hech narsa qaytarmaydi:
function qosh(a: number, b: number): number {
console.log(a + b);
// β Xato: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
}
Bu juda foydali: return tipini yozish "men albatta qiymat qaytaraman" degan va'da, va compiler shu va'dani tekshiradi.
Return inference β TS o'zi topadi¶
Parametrlarga tip yozish deyarli har doim shart. Ammo return tipini ko'pincha yozmaslik mumkin β TypeScript uni return qatoriga qarab o'zi aniqlaydi. Buni inference ("xulosa chiqarish") deyiladi:
function kvadrat(n: number) {
return n * n; // number * number β TS return tipini number deb biladi
}
const natija = kvadrat(4); // natija avtomatik number
kvadrat ustiga sichqonchani olib borsangiz, muharrir function kvadrat(n: number): number deb ko'rsatadi β garchi siz : number yozmagan bo'lsangiz ham.
π‘ Qoida: parametrlarga tip yozing, return tipini esa odatda TS'ga qoldiring. Lekin eksport qilinadigan (boshqa fayllar ishlatadigan) funksiyalarda return tipini yozish afzal β bu funksiya niyatini hujjatlashtiradi va keyinchalik tanani o'zgartirib qaytim tipini bilmasdan buzib qo'yishdan saqlaydi.
void β qaytarmaydigan funksiya¶
Ba'zi funksiyalar qiymat qaytarmaydi β ular faqat ish bajaradi (konsolga yozadi, fayl saqlaydi, ekranni yangilaydi). Ularning return tipi β void ("hech narsa"):
void aytadi: "bu funksiya foydali qiymat qaytarmaydi, uning natijasini o'zgaruvchiga olmang". Agar olsangiz:
π void va undefined β bir xil emas. Texnik jihatdan void funksiya ish vaqtida undefined qaytaradi (JS'dagi har bir returnsiz funksiya kabi). Ammo void β bu "qaytimni e'tiborga olma" degan niyat, undefined esa konkret qiymat. Amalda: "hech narsa qaytarmaydi" demoqchi bo'lsangiz void ishlating, undefinedni emas.
π‘ voidning nozik, lekin muhim xususiyati: void tipidagi callback aslida biror qiymat qaytarsa ham, TS uni e'tiborga olmaydi. Bu ataylab shunday qilingan β quyidagi keng tarqalgan kod ishlashi uchun:
const sonlar = [1, 2, 3];
const yangi: number[] = [];
// forEach callback'i void kutadi, push() esa number qaytaradi β
// lekin TS bunga xato bermaydi, chunki void qaytim e'tiborga olinmaydi:
sonlar.forEach((x) => yangi.push(x)); // β
toza o'tadi
Agar void qat'iy "faqat undefined" deganda edi, bu juda foydali qolip har safar xato berardi. Esda tuting: void return tipi β "men qaytimingni o'qimayman" degani, "sen hech narsa qaytarma" degani emas.
Optional ?, default qiymat va rest¶
Parametrlar har doim ham majburiy emas. TypeScript ularni moslashuvchan qilishning uch yo'lini beradi.
Optional parametr β ?¶
Parametr nomidan keyin ? qo'ysangiz, u ixtiyoriy bo'ladi. Berilmasa, qiymati undefined:
function tabrikla(ism: string, unvon?: string): string {
if (unvon) {
return unvon + " " + ism;
}
return ism;
}
tabrikla("Lola"); // "Lola"
tabrikla("Lola", "ustoz"); // "ustoz Lola"
unvonning tipi aslida string | undefined β shuning uchun uni ishlatishdan oldin if (unvon) bilan tekshirish kerak (buni narrowing deyiladi, 8-bobda chuqur ko'ramiz). Tekshirmasangiz, unvon undefined bo'lishi mumkinligini compiler eslatadi.
π Optional parametrlar oxirda turishi shart. Majburiy parametr optional'dan keyin kela olmaydi β bu mantiqsiz bo'lardi:
function f(a?: string, b: number): void {} // β Xato: A required parameter cannot follow an optional parameter.
Default qiymat¶
? o'rniga parametrga default qiymat berishingiz mumkin. Argument berilmasa, shu qiymat ishlatiladi:
function kuchaytir(asos: number, daraja: number = 2): number {
return asos ** daraja;
}
kuchaytir(5); // 25 (daraja default 2 boldi)
kuchaytir(5, 3); // 125
π‘ Default qiymatda tip annotation yozish shart emas: daraja = 2dan TS uning number ekanini o'zi biladi. Default qiymatli parametr ham avtomatik ixtiyoriy bo'ladi β ? qo'shish kerak emas (ikkalasini birga ishlatish ham mumkin emas).
Rest parametr β ...¶
Nechta argument kelishini oldindan bilmasangiz, rest parametr ishlating. U barcha qolgan argumentlarni bitta massivga yig'adi:
function yigindi(...sonlar: number[]): number {
return sonlar.reduce((jami, x) => jami + x, 0);
}
yigindi(1, 2, 3); // 6
yigindi(10, 20, 30, 40); // 100
...sonlar: number[] β "qancha kelsa ham, hammasini numberlar massivi sifatida qabul qil". Tipni number[] deb yozganimiz uchun, matn qo'shib bo'lmaydi:
yigindi(1, 2, "uch"); // β Xato: Argument of type 'string' is not assignable to parameter of type 'number'.
π Rest parametr doim eng oxirgi bo'lishi kerak β undan keyin boshqa parametr bo'la olmaydi, chunki u qolgan hamma argumentni o'ziga oladi.
Funksiya tipi β (a: number) => string¶
Hozirgacha funksiyalarni e'lon qildik. Endi esa funksiyaning o'zini tip sifatida yozishni o'rganamiz β bu callback'lar va funksiyani o'zgaruvchida saqlash uchun zarur.
Funksiya tipining sintaksisi: (parametrlar) => qaytim_tipi. E'tibor bering β bu yerda => arrow funksiya emas, tip belgisi:
let amal: (a: number, b: number) => number;
amal = (a, b) => a * b; // mos: ikki number olib, number qaytaradi
amal(3, 4); // 12
amal o'zgaruvchisining tipi β "ikki number qabul qilib number qaytaradigan funksiya". Diqqat qiling: (a, b) => a * b ichida a va bga tip yozmadik. TS ularni amalning e'lon qilingan tipidan oladi β buni contextual typing ("kontekstdan tip olish") deyiladi. Funksiya tipini bir marta belgilasangiz, ichkaridagi parametrlarni qayta tiplash shart emas.
type bilan nom berish¶
Bir xil funksiya tipini ko'p joyda ishlatsangiz, unga type orqali nom bering β bu kodni toza qiladi:
type Op = (a: number, b: number) => number;
const qoshish: Op = (a, b) => a + b;
const ayirish: Op = (a, b) => a - b;
const kopaytirish: Op = (a, b) => a * b;
Op endi qayta ishlatiladigan "shakl". Funksiya bu shaklga mos kelmasa, compiler darrov ushlaydi:
type Op = (a: number, b: number) => number;
const ayir: Op = (a, b) => a > b; // β Xato: Type 'boolean' is not assignable to type 'number'.
Bu yerda funksiya boolean (a > b) qaytaryapti, Op esa number kutadi β tip mos kelmadi.
π‘ Funksiya tipini interface ichida ham yozish mumkin (5-bobdagi object tiplarini eslang):
interface Kalkulyator {
nom: string;
bajar: (a: number, b: number) => number;
}
const oddiy: Kalkulyator = {
nom: "qoshuvchi",
bajar: (a, b) => a + b,
};
Callback'larni tiplash¶
Callback β bu boshqa funksiyaga argument sifatida uzatiladigan funksiya. map, filter, forEach, addEventListener β hammasi callback qabul qiladi. TypeScript callback'ning imzosini ham tekshiradi.
Eng yaxshi yangilik: callback'lardagi parametrlarga ko'pincha tip yozish shart emas, TS uni o'zi biladi:
const sonlar = [1, 2, 3, 4];
const juftlar = sonlar.filter((x) => x % 2 === 0); // x avtomatik number
const matnlar = sonlar.map((x) => "β" + x); // x avtomatik number, natija string[]
sonlar β number[] bo'lgani uchun, TS filter va map callback'idagi xni number deb biladi. Bu β yuqorida ko'rgan contextual typing'ning aynan o'zi.
Endi o'z funksiyangizga callback qabul qilaylik. Callback parametrini funksiya tipi bilan tiplaymiz:
type Op = (a: number, b: number) => number;
function ishlat(a: number, b: number, op: Op): number {
return op(a, b);
}
ishlat(6, 7, (x, y) => x + y); // 13
ishlat(6, 7, (x, y) => x * y); // 42
op: Op β uchinchi argument funksiya bo'lishi va Op shakliga mos kelishi shart. Callback ichidagi x va yni tiplamadik β TS ularni Opdan oldi.
π Compiler callback imzosini ham tekshiradi. Quyida Filtr boolean qaytaruvchi callback kutadi, biz esa number qaytaryapmiz:
type Filtr = (x: number) => boolean;
const musbat: Filtr = (x) => x; // β Xato: Type 'number' is not assignable to type 'boolean'.
Yuqori tartibli funksiyalar (HOF)¶
Yuqori tartibli funksiya (higher-order function, HOF) β bu funksiyani qabul qiladigan yoki funksiyani qaytaradigan funksiya. Yuqoridagi ishlat β funksiya qabul qildi. Endi funksiya qaytaruvchisini ko'raylik:
function kopaytuvchi(koeff: number): (x: number) => number {
return (x) => x * koeff;
}
const ikkilantir = kopaytuvchi(2);
const uchlantir = kopaytuvchi(3);
ikkilantir(21); // 42
uchlantir(10); // 30
Diqqat β return tipiga qarang: : (x: number) => number. Bu "men number olib number qaytaradigan funksiya qaytaraman" degani. kopaytuvchi(2) chaqirilganda, ichki funksiya tashqi koeffni "eslab qoladi" (JS'dagi closure) va ikkilantirga aylanadi.
π‘ HOF qaytim tipini yozish murakkab ko'rinadi, shuning uchun ko'pincha uni type bilan soddalashtirgan ma'qul:
type SonAmali = (x: number) => number;
function kopaytuvchi(koeff: number): SonAmali {
return (x) => x * koeff;
}
Massiv ustida ishlovchi tipik HOF β bu callback'ni har bir elementga qo'llaydigan funksiya:
function qoshHar(arr: number[], op: (x: number) => number): number[] {
return arr.map(op);
}
qoshHar([1, 2, 3], (x) => x * 10); // [10, 20, 30]
Overload β bitta nom, bir nechta imzo¶
Ba'zan bitta funksiya turli xil kirishlarni qabul qilib, kirishga qarab turli xil qaytim beradi. Masalan, string bersangiz string, number bersangiz number qaytarsin. Buni overload (imzo qatlamlash) orqali aniq ifodalash mumkin.
Overload uch qismdan iborat: bir nechta imzo qatorlari (tana yo'q) va ulardan keyin bitta amaliy tana:
// Overload imzolari (tanasiz):
function aralashtir(a: string, b: string): string;
function aralashtir(a: number, b: number): number;
// Amaliy tana (bu imzo tashqaridan ko'rinmaydi):
function aralashtir(a: any, b: any): any {
return a + b;
}
const matn = aralashtir("Salom, ", "dunyo"); // tipi: string
const son = aralashtir(2, 3); // tipi: number
Endi matn aniq string, son aniq number β any emas. Chaqiruvchi to'g'ri qaytim tipini oladi. Agar overload'siz, oddiy (a: number | string, b: number | string) deb yozsak, qaytim har doim number | string bo'lib qolardi va har safar tekshirishga to'g'ri kelardi.
π Amaliy tanadagi any va keng imzo faqat funksiya ichida ko'rinadi β tashqaridan u umuman chaqirib bo'lmaydi. Tashqi dunyo faqat tepadagi ikki "toza" imzoni ko'radi. Shuning uchun ichki tana barcha imzolarni qoplaydigan darajada keng bo'lishi kerak.
Ko'proq foydali misol β kirish tipiga qarab boshqacha amal:
function teskari(x: string): string;
function teskari(x: number[]): number[];
function teskari(x: string | number[]): string | number[] {
if (typeof x === "string") {
return x.split("").reverse().join("");
}
return x.slice().reverse();
}
teskari("abc"); // "cba" (tipi: string)
teskari([1, 2, 3]); // [3, 2, 1] (tipi: number[])
π‘ Overload'ni kamroq ishlating. Zamonaviy TypeScript'da ko'p hollarda overload o'rniga generic (11-bob) yoki union tip ishlatish soddaroq va kuchliroq bo'ladi. Overload'ni faqat "kirishga qarab qaytim tubdan o'zgaradi" degan haqiqiy ehtiyoj bo'lganda tanlang.
this parametri¶
Method (object ichidagi funksiya) ichida this β o'sha object'ga ishora qiladi. Lekin this funksiya qanday chaqirilishiga qarab o'zgaradi, va bu JS'dagi klassik tuzoq. TypeScript buni maxsus this parametri orqali nazorat qiladi.
this parametri β parametrlar ro'yxatidagi birinchi "soxta" parametr. U faqat tip uchun; haqiqiy argument emas va chaqirishda berilmaydi:
interface Tugma {
matn: string;
bos(this: Tugma): void;
}
const tugma: Tugma = {
matn: "Saqlash",
bos(this: Tugma) {
console.log(this.matn + " bosildi");
},
};
tugma.bos(); // "Saqlash bosildi"
bos(this: Tugma) aytadi: "bu method faqat Tugma kontekstida chaqirilishi mumkin". Endi method'ni object'dan ajratib olib chaqirsangiz, this yo'qoladi va compiler ushlaydi:
const ajratilgan = tugma.bos; // method object'dan ajratildi
ajratilgan(); // β Xato: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Tugma'.
π Bu xato JS'dagi eng mashhur runtime tuzoqlardan birini (Cannot read properties of undefined) compile vaqtida ushlaydi. JS'da bu kod jimgina ishlab, keyin this.matnda yiqilardi. TS esa oldindan ogohlantiradi.
π‘ this parametrini faqat oddiy funksiya/method'da ishlatish mumkin. Arrow funksiyada this yo'q β arrow funksiya thisni o'rab turgan kontekstdan oladi va uni o'zgartirib bo'lmaydi. Shuning uchun arrow funksiyaga this parametri yoza olmaysiz (va odatda kerak ham emas).
Xulosa¶
Funksiyalarni tiplash β TypeScript'ning amaliy yuragi:
- Parametrlarga tip yozing, return tipini ko'pincha TS'ga qoldiring (inference). Eksport funksiyalarda return tipini yozish afzal.
voidβ qaytarmaydigan funksiya; "qaytimingni o'qimayman" degani, shuning uchunvoidcallback baribir qiymat qaytarishi mumkin.?β optional parametr (undefinedbo'lishi mumkin),= qiymatβ default,...args: T[]β rest. Optional va rest doim oxirda.(a: T) => Rβ funksiya tipi;type Op = ...bilan nom bering. Callback parametrlari kontekstdan tip oladi β qayta tiplash shart emas.- HOF β funksiya qabul qiluvchi yoki qaytaruvchi funksiya; qaytim funksiya tipini
typebilan soddalashtiring. - Overload β bitta nom, bir nechta imzo; kamroq ishlating, ko'pincha generic afzal.
thisparametri β method'ni noto'g'ri kontekstda chaqirishni compile vaqtida ushlaydi.
Keyingi bobda union va literal tiplarni o'rganamiz β "yangi" | "jarayonda" | "tugadi" kabi cheklangan qiymatlar to'plamini va ularni funksiya parametrlarida qanday ishlatishni ko'ramiz.
6-bob mashqlari¶
Quyidagi mashqlarni o'zingiz yozib bajaring. Har birini tsc --noEmit --strict bilan tekshiring: toza bo'lishi kerak bo'lganlar xatosiz o'tsin, ataylab xato so'ralganlarda esa compiler aynan kutilgan xabarni bersin.
kvadrat(n: number): numberfunksiyasini yozing β sonning kvadratini qaytarsin. Keyinkvadrat("4")deb chaqirib, compiler qanday xato berishini ko'ring.katta(a: number, b: number): numberfunksiyasini yozing β ikki sondan kattasini qaytarsin. Return tipini yozmasdan ham sinab ko'ring va muharrirda TS uni qanday aniqlaganini tekshiring.chiqar(xabar: string): voidfunksiyasini yozing β xabarni konsolga chiqarsin. Keyin uning natijasiniconst x: string = chiqar("salom")deb olishga urinib, xatoni ko'ring.voidqaytaradigan callback aslida qiymat qaytarsa ham xato bermasligini isbotlang:[1,2,3].forEach((x) => yangiMassiv.push(x))qolipini yozib, toza o'tishini tekshiring.salomla(ism: string, unvon?: string): stringfunksiyasini yozing βunvonbo'lsa "unvon ism", bo'lmasa faqat "ism" qaytarsin. Ikki xil chaqirib sinang.- Optional parametrni majburiy parametrdan oldin qo'yib (
function f(a?: number, b: number)), compiler bergan xatoni o'qing va nima uchun shunday ekanini izohlang. salyut(daraja: number = 1): stringfunksiyasini yozing βdarajamarta "!" qaytarsin ("!".repeat(daraja)). Argumentsiz chaqirib, default ishlaganini tekshiring.kopaytir(...sonlar: number[]): numberfunksiyasini yozing β barcha argumentlar ko'paytmasini qaytarsin (bo'sh kelsa 1).reduceishlating.- Rest parametrga matn uzatib (
kopaytir(2, 3, "x")) compiler xatosini ko'ring. - Rest parametrdan keyin yana bir parametr qo'yishga urinib (
function f(...a: number[], b: number)), compiler nima deyishini tekshiring. type Amal = (a: number, b: number) => numbertip aliasini e'lon qiling. Unga mosqoshvaayirfunksiyalarini yarating.- 11-mashqdagi
Amalga mos kelmaydigan funksiya bering (masalan(a, b) => a > b) va return tipi mos kelmagani haqidagi xatoni ko'ring. qoLla(a: number, b: number, op: (x: number, y: number) => number): numberfunksiyasini yozing βopniavabga qo'llab natijani qaytarsin. Uni har xil callback bilan chaqiring.[5, 2, 8, 1]massivinifilterbilan faqat 3 dan kattalarni qoldiring. Callback parametrixga tip yozmang va TS uninumberdeb bilganini muharrirda tekshiring.stringvanumber[]ni uzunligiga qarabnumberqaytaruvchiuzunlikfunksiyasini overload bilan yozing:uzunlik(x: string): numbervauzunlik(x: number[]): number. Ichidatypeof/Array.isArraybilan ajrating.formatfunksiyasini overload bilan yozing:numberbersangizstring("$" + son),booleanbersangizstring("ha"/"yoq") qaytarsin. Qaytim tiplari to'g'ri ekanini tekshiring.kopaytuvchiYasa(koeff: number): (x: number) => numberHOF'ini yozing βkoeffga ko'paytiradigan funksiya qaytarsin.const besh = kopaytuvchiYasa(5); besh(4)β 20 ekanini tekshiring.qayta(arr: number[], n: number, op: (x: number) => number): number[]funksiyasini yozing βopni har elementganmarta ketma-ket qo'llasin. Bir necha callback bilan sinang.interface Hisoblagich { soni: number; oshir(this: Hisoblagich): void }e'lon qiling vaoshirthis.sonini bittaga oshirsin. To'g'ri chaqirib, ishlaganini tekshiring.- 19-mashqdagi
oshirmethod'ini object'dan ajratib (const f = obj.oshir; f()) chaqiring vathiskonteksti haqidagi compiler xatosini o'qing. Nega arrow funksiyadathisparametri yoza olmasligimizni bir jumlada izohlang.