Ders 10 / 23
Fonksiyon Tipleri
Fonksiyon tipi yazımı, seçmeli ve kalan parametreler, void dönüş tipinin özel davranışı, parametre sayısı kuralı, aşırı yükleme ve this parametresi.
İçindekiler
Önceki derste sınıf yöntemleri ve tek başına duran fonksiyonlar kullanıldı ama tiplerinin
nasıl yazıldığı ele alınmadı. Bir fonksiyonun tipi parametre ve dönüş tiplerinden ibaret
değildir: seçmeli parametreler, kalan parametreler, çağrı biçimine göre değişen dönüş
tipleri ve this bağlamı da tipin parçasıdır.
Bu ders bu bileşenleri sırayla kurar ve ölçüm kaydını okuyan bir ayrıştırıcı üzerinde uygular.
Fonksiyon Tipi Yazımı
Bir fonksiyon tipi, parametre listesi ve ok işaretinden sonra dönüş tipiyle yazılır:
type Olcum = { kimlik: string; deger: number }; type Suzgec = (olcum: Olcum) => boolean; function suz(kayitlar: readonly Olcum[], olcut: Suzgec): Olcum[] { return kayitlar.filter(olcut); } const pozitif: Suzgec = (o) => o.deger > 0; const kayitlar: Olcum[] = [ { kimlik: "s-01", deger: 21.4 }, { kimlik: "s-02", deger: -3 }, ]; console.log(suz(kayitlar, pozitif).length); const yanlis: Suzgec = (o) => o.deger;
j1.ts(16,31): error TS2322: Type 'number' is not assignable to type 'boolean'.
pozitif bildiriminde o parametresine tip yazılmamıştır; tip, bağlamsal tipleme yoluyla
Suzgec tanımından gelir. Son satır ise dönüş tipi uymadığı için reddedilir —
JavaScript’te doğruluk değeri olarak kullanılabilecek bir sayı, boolean beklenen yere
konamaz.
Fonksiyon tipindeki parametre adları (olcum) belgeleme amaçlıdır; uyumlulukta rol
oynamazlar. Önemli olan sıra ve tiptir.
Seçmeli, Varsayılan ve Kalan Parametreler
type Olcum = { kimlik: string; deger: number; not?: string }; function olustur( kimlik: string, deger: number, birim: string = "C", ...etiketler: string[] ): string { return `${kimlik}=${deger}${birim} [${etiketler.join(",")}]`; } console.log(olustur("s-01", 21.4)); console.log(olustur("s-02", 101325, "Pa", "kazan", "vardiya-3")); function yaz(olcum: Olcum): string { return olcum.not.trim(); } console.log(yaz({ kimlik: "s-03", deger: 1 }));
j2.ts(16,10): error TS18048: 'olcum.not' is possibly 'undefined'.
birim parametresinin varsayılan değeri vardır; tipi string olarak çıkarılır ve
çağrıda atlanabilir. etiketler kalan parametredir; tipi bir dizidir ve her zaman
tanımlıdır — atlanırsa boş dizi olur.
Son tanı, seçmeli alanların bedelini gösterir: not?: string bildirimi alanın tipini
string | undefined yapar ve undefined üzerinde trim çağrılamaz. Derleyici, atlanan
denetimi bildirir. Düzeltme daraltmadır: olcum.not?.trim() ?? "" ya da açık bir if
bloğu.
Bu davranış strictNullChecks seçeneğine bağlıdır. Seçenek kapalıyken undefined her
tipe atanabilir ve bu tanı gelmez — kapalı bir yapılandırmada seçmeli alanlar hiçbir
güvence taşımaz.
void Dönüş Tipinin Özel Davranışı
void, “dönüş değeri kullanılmayacak” anlamına gelir. Beklenenden gevşek bir kuralı
vardır:
type Olcum = { kimlik: string; deger: number }; type Kaydedici = (olcum: Olcum) => void; const kayitlar: Olcum[] = []; const ekle: Kaydedici = (olcum) => kayitlar.push(olcum); ekle({ kimlik: "s-01", deger: 21.4 }); console.log(kayitlar.length); const sonuc = ekle({ kimlik: "s-02", deger: 22.1 }); console.log(sonuc.toFixed(0));
j3.ts(11,19): error TS2339: Property 'toFixed' does not exist on type 'void'.
Beşinci satır hata vermez. kayitlar.push(olcum) ifadesi bir sayı döndürür, oysa
Kaydedici tipi void dönüş bildirir. Kural şudur: dönüş değeri olan bir fonksiyon,
void dönen bir tipe atanabilir. Gerekçe, void bildiriminin “hiçbir şey döndürme”
değil “döndürdüğün şey kullanılmayacak” demesidir.
Bunun sonucu on birinci satırda görülür: çağrı yerinden bakıldığında dönüş tipi voidtir
ve üzerinde işlem yapılamaz. Değer gerçekte vardır, tip sistemi onu görmeyi reddeder.
Bu kural, geri çağrı alan fonksiyonların kullanımını kolaylaştırır. forEach yönteminin
geri çağrısı void döner; her geri çağrının dönüşsüz yazılması zorunlu olsaydı,
(o) => kayitlar.push(o) gibi kısa yazımlar reddedilirdi.
Parametre Sayısı Kuralı
Fonksiyon uyumluluğunda parametre sayısı tek yönlü çalışır:
type Olcum = { kimlik: string; deger: number }; type Geri = (olcum: Olcum, sira: number) => void; const yalnizKayit: Geri = (olcum) => console.log(olcum.kimlik); yalnizKayit({ kimlik: "s-01", deger: 21.4 }, 0); const fazla: Geri = (olcum, sira, ek: string) => console.log(ek);
j4.ts(7,7): error TS2322: Type '(olcum: any, sira: any, ek: string) => void' is not assignable to type 'Geri'. Target signature provides too few arguments. Expected 3 or more, but got 2. j4.ts(7,22): error TS7006: Parameter 'olcum' implicitly has an 'any' type. j4.ts(7,29): error TS7006: Parameter 'sira' implicitly has an 'any' type.
Daha az parametre alan bir fonksiyon, daha çok parametre bildiren bir tipe atanabilir; fazladan gelen argümanları yok sayar. Daha çok parametre alan bir fonksiyon atanamaz — çağıran o argümanı sağlamayacaktır.
Bu, JavaScript’in çağrı kuralının doğrudan yansımasıdır: fazladan argüman hataya yol
açmaz, eksik argüman undefined olur. Tip sistemi ilkine izin verir, ikincisini engeller.
Son iki tanıya dikkat: yedinci satırda olcum ve sira parametreleri bağlamsal tiplerini
kaybetmiştir. Atama başarısız olduğu için bağlam kurulamamış, parametreler örtük any
olarak kalmıştır. Tek bir hatanın birden çok tanı üretmesi sık görülür; kaynak tanı ilk
olandır.
Aşırı Yükleme
Bir fonksiyon, argümanın tipine göre farklı dönüş tipleri veriyorsa aşırı yükleme (overloading) ile bildirilir:
type Olcum = { kimlik: string; deger: number }; function birKayit(ham: string): Olcum | null { const parcalar = ham.split("="); if (parcalar.length !== 2) { return null; } const deger = Number(parcalar[1]); return Number.isFinite(deger) ? { kimlik: parcalar[0], deger } : null; } function oku(ham: string): Olcum | null; function oku(ham: readonly string[]): Olcum[]; function oku(ham: string | readonly string[]): Olcum | Olcum[] | null { if (typeof ham === "string") { return birKayit(ham); } return ham.map(birKayit).filter((o): o is Olcum => o !== null); } const tek = oku("s-01=21.4"); const cok = oku(["s-01=21.4", "bozuk", "s-02=22.1"]); console.log(tek?.deger); console.log(cok.length, cok.map((o) => o.kimlik).join(","));
Çıktı:
21.4 2 s-01,s-02
Üç imza vardır ama yalnızca ikisi çağrılabilir. İlk iki satır çağrı imzalarıdır;
üçüncüsü gerçekleştirim imzasıdır ve dışarıdan görünmez. tek bildiriminin tipi
Olcum | null, cok bildiriminin tipi Olcum[]tir — tek bir birleşim tipi yerine, çağrı
biçimine göre kesin tip.
Gerçekleştirim imzasının çağrılamaması, birleşim tipli bir argümanla denendiğinde görünür. Yukarıdaki dosyanın sonuna, bir boş satırdan sonra şu üç satır eklenirse:
declare const belirsiz: string | readonly string[]; const belirsizSonuc = oku(belirsiz); console.log(belirsizSonuc);
j8.ts(28,27): error TS2769: No overload matches this call.
Overload 1 of 2, '(ham: string): Olcum | null', gave the following error.
Argument of type 'string | readonly string[]' is not assignable to parameter of type 'string'.
Type 'readonly string[]' is not assignable to type 'string'.
Overload 2 of 2, '(ham: readonly string[]): Olcum[]', gave the following error.
Argument of type 'string | readonly string[]' is not assignable to parameter of type 'readonly string[]'.
Type 'string' is not assignable to type 'readonly string[]'.
Tanı iki çağrı imzasını da dener ve ikisinin de neden uymadığını yazar; gerçekleştirim imzasından hiç söz etmez. Çağıranın bu durumda yapması gereken, argümanı çağrıdan önce daraltmaktır.
Aşırı yükleme yalnızca tip düzeyinde bir bildirimdir. Derlenmiş çıktıda tek bir fonksiyon
kalır ve dallanmayı gerçekleştirim gövdesi yapar — typeof ham === "string" sınaması
buradadır.
this Parametresi
Bir fonksiyonun hangi bağlamda çağrılacağı da tiplenebilir. İlk parametre adı this
olduğunda, o parametre gerçek bir parametre değil bağlam bildirimidir:
type Defter = { ad: string; kayitlar: number[] }; function ozet(this: Defter): string { return `${this.ad}: ${this.kayitlar.length}`; } const defter: Defter & { ozet: () => string } = { ad: "kazan-2", kayitlar: [21.4, 22.1], ozet, }; console.log(defter.ozet());
Çıktı kazan-2: 2dir. Dosyanın sonuna console.log(ozet()); satırı eklenirse:
baglam.ts(14,13): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'Defter'.
JavaScript’te Nesneler ve Fonksiyonlar kursunda kurulan this bağlanma kuralları burada
tip düzeyinde sınanır: nesneden koparılarak çağrılan bir yöntemin bağlamı kaybolur ve
derleyici bunu bildirir.
this parametresi de tümüyle silinir. Yukarıdaki dosyanın derlenmiş çıktısında fonksiyon
imzası boştur:
function ozet() { return `${this.ad}: ${this.kayitlar.length}`; }
Özet
- Fonksiyon tipi parametre listesi ve dönüş tipiyle yazılır; parametre adları uyumlulukta rol oynamaz.
- Seçmeli alan ve parametreler tipe
undefinedekler; kullanılmadan önce daraltılmaları gerekir. - Dönüş değeri olan bir fonksiyon
voiddönen tipe atanabilir, ancak çağrı yerinde dönüş değeri kullanılamaz. - Daha az parametre alan fonksiyon daha çok parametreli tipe atanabilir; tersi atanamaz.
- Aşırı yüklemede çağrı imzaları dışarıdan görünür, gerçekleştirim imzası görünmez; dallanma çalışma zamanında gövdede yapılır.
thisparametresi bağlamı tipler ve tümüyle silinir.
Sonraki Adım
Bu konudaki örneklerin hiçbirinde bir değer, uyduğu tipin adını yazmadı: nesne sabitleri arayüzlere, fonksiyonlar fonksiyon tiplerine yalnızca biçimleri uyduğu için kabul edildi. Bu, TypeScript’in tip uyumluluğunun temel kuralıdır ve beklenmedik sonuçları vardır. Sonraki ders yapısal tiplemenin kurallarını, fazlalık özellik denetimini ve yapısal uyumluluğun aşılması gereken durumları ele alacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.