İçeriğe geç
academia.sh

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 undefined ekler; kullanılmadan önce daraltılmaları gerekir.
  • Dönüş değeri olan bir fonksiyon void dö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.
  • this parametresi 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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat