---
title: Genellikler
source: 'https://academia.sh/tr/kurslar/typescript/genellikler'
course: TypeScript
language: tr
updated: '2026-08-17T18:09:53+00:00'
license: 'CC BY-SA 4.0'
---

# Genellikler

Tip parametreleriyle biçimden bağımsız yapılar yazma, tip argümanı çıkarımı, kısıtlar, keyof kısıtı, varsayılan tip parametreleri ve genelliğin kötüye kullanımı.

Önceki konudaki tiplerin tümü belirliydi: `Olcum` kayıtları tutan bir defter, `Olcum` alan
bir süzgeç. Oysa defterin yapısı kayıt tipinden bağımsızdır — aynı kod ölçümleri,
uyarıları veya olayları toplamalıdır.

Bunu sağlamanın iki kötü yolu vardır. Her kayıt tipi için ayrı bir defter yazmak kodu
çoğaltır; deftere `any[]` kullandırmak ise tip güvencesini kaldırır. **Genellik**
(generic), üçüncü yolu verir: yapıyı bir **tip parametresiyle** yazmak ve tipi kullanım
yerinde vermek.

## Tip Parametreli Yapılar

Tip parametresi, bildirim adından sonra açılı ayraç içinde yazılır ve gövde boyunca bir
tip gibi kullanılır:

```typescript
interface Olcum {
  kimlik: string;
  deger: number;
}

class Defter<T> {
  private kayitlar: T[] = [];

  ekle(kayit: T): void {
    this.kayitlar.push(kayit);
  }

  sonuncu(): T | undefined {
    return this.kayitlar.at(-1);
  }

  get sayi(): number {
    return this.kayitlar.length;
  }
}

const olcumler = new Defter<Olcum>();
olcumler.ekle({ kimlik: "s-01", deger: 21.4 });
console.log(olcumler.sonuncu()?.deger, olcumler.sayi);

const uyarilar = new Defter<string>();
uyarilar.ekle("sensor yanit vermiyor");
console.log(uyarilar.sonuncu()?.toUpperCase());
```

Çıktı:

```text
21.4 1
SENSOR YANIT VERMIYOR
```

Tek bir sınıf iki farklı kayıt tipiyle kullanıldı ve her kullanımda tip bilgisi korundu:
`olcumler.sonuncu()` çağrısı `Olcum | undefined`, `uyarilar.sonuncu()` çağrısı
`string | undefined` verir. Dosyanın sonuna, bir boş satırdan sonra
`olcumler.ekle("s-02");` satırı eklenirse:

```text
m1.ts(30,15): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Olcum'.
```

`any[]` çözümü bu tanıyı üretmezdi. Genellik, ortak yapıyı paylaşırken tip güvencesini
kaybetmemenin yoludur.

Dönüş tipinin `T | undefined` olması da tasarımın parçası: `at(-1)` çağrısı boş bir dizide
`undefined` verir ve tip bunu kaydeder. Çağıran, `?.` yazımıyla bu olasılığı ele almak
zorundadır.

## Tip Argümanı Çıkarımı

Tip argümanı çoğu zaman yazılmaz; derleyici argümanlardan çıkarır:

```typescript
function ilk<T>(kayitlar: readonly T[]): T | undefined {
  return kayitlar[0];
}

const sayi = ilk([21.4, 22.1]);
const metin = ilk(["s-01", "s-02"]);
console.log(sayi?.toFixed(1), metin?.toUpperCase());
```

Çıktı `21.4 S-01`dir.

`ilk<number>` ve `ilk<string>` yazımlarına gerek kalmamıştır. `sayi` bildiriminin tipi
`number | undefined`, `metin` bildiriminin tipi `string | undefined` olarak çıkarılır ve
her birinde o tipin yöntemleri kullanılabilir.

Çıkarımın çalışması için tip parametresinin **argümanlarda geçmesi** gerekir. Yalnızca
dönüş tipinde geçen bir tip parametresi çıkarılamaz; bu durumun tehlikesi dersin sonunda
ele alınacaktır.

## Kısıtlar

Tip parametresi hiçbir şey bilinmeyen bir tiptir; üzerinde işlem yapılamaz. Belirli üyelere
erişmek için parametreye **kısıt** (constraint) yazılır:

```typescript
interface Kimlikli {
  kimlik: string;
}

function kimlikleriTopla<T extends Kimlikli>(kayitlar: readonly T[]): string[] {
  return kayitlar.map((k) => k.kimlik);
}

console.log(kimlikleriTopla([{ kimlik: "s-01", deger: 21.4 }]));
console.log(kimlikleriTopla([{ ad: "kazan-2" }]));
```

```text
m4.ts(10,32): error TS2353: Object literal may only specify known properties, and 'ad' does not exist in type 'Kimlikli'.
```

`T extends Kimlikli` bildirimi iki iş yapar: gövdede `k.kimlik` erişimini olanaklı kılar
ve uymayan argümanları çağrı yerinde reddeder. Dokuzuncu satırın kabul edilmesi de önemli
— `deger` alanı fazlalıktır, kısıt yalnızca en az gerekliliği belirtir.

Kısıt yazmadan `k.kimlik` yazılsaydı derleyici erişimi reddederdi: `T` herhangi bir tip
olabilir, dizgi de olabilir, sayı da.

## `keyof` ile Kısıt

Kısıtlar başka tip parametrelerine de başvurabilir. En kullanışlı biçimi, bir tipin alan
adlarını veren `keyof` işleciyle kurulur:

```typescript
interface Olcum {
  kimlik: string;
  deger: number;
  birim: "C" | "Pa" | "%";
}

function alan<T, A extends keyof T>(kayit: T, ad: A): T[A] {
  return kayit[ad];
}

const kayit: Olcum = { kimlik: "s-01", deger: 21.4, birim: "C" };
const d: number = alan(kayit, "deger");
const b: "C" | "Pa" | "%" = alan(kayit, "birim");
console.log(d, b);

alan(kayit, "konum");
```

```text
m5.ts(16,13): error TS2345: Argument of type '"konum"' is not assignable to parameter of type 'keyof Olcum'.
```

Üç yeni yazım var. `keyof T`, `T` tipinin alan adlarının sabit tiplerinden oluşan bir
birleşimdir — burada `"kimlik" | "deger" | "birim"`. `A extends keyof T` kısıtı, ikinci
argümanı bu adlarla sınırlar. `T[A]` ise **indeksli erişim tipidir** (indexed access
type): `A` adlı alanın tipini verir.

Sonuç, alan adına göre değişen bir dönüş tipidir. `alan(kayit, "deger")` çağrısının tipi
`number`, `alan(kayit, "birim")` çağrısının tipi `"C" | "Pa" | "%"`tir. Aşırı yükleme
yazmadan, alan sayısı kadar farklı imza elde edilmiştir.

## Varsayılan Tip Parametresi

Tip parametrelerine varsayılan değer verilebilir. Sınırda doğrulamanın sonucunu taşıyan
tip bunun tipik kullanımıdır:

```typescript
type Sonuc<D, H = string> =
  | { durum: "basarili"; deger: D }
  | { durum: "hatali"; hata: H };

interface Olcum {
  kimlik: string;
  deger: number;
}

function oku(ham: string): Sonuc<Olcum> {
  const parcalar = ham.split("=");
  if (parcalar.length !== 2) {
    return { durum: "hatali", hata: `bicim gecersiz: ${ham}` };
  }
  const deger = Number(parcalar[1]);
  if (!Number.isFinite(deger)) {
    return { durum: "hatali", hata: `sayi degil: ${parcalar[1]}` };
  }
  return { durum: "basarili", deger: { kimlik: parcalar[0], deger } };
}

function yaz(sonuc: Sonuc<Olcum>): string {
  return sonuc.durum === "basarili"
    ? `${sonuc.deger.kimlik}=${sonuc.deger.deger}`
    : `hata: ${sonuc.hata}`;
}

console.log(yaz(oku("s-01=21.4")));
console.log(yaz(oku("bozuk")));
console.log(yaz(oku("s-02=abc")));
```

Çıktı:

```text
s-01=21.4
hata: bicim gecersiz: bozuk
hata: sayi degil: abc
```

`Sonuc<Olcum>` yazımında ikinci tip argümanı verilmemiş, varsayılan `string`
kullanılmıştır. Hata tipinin ayrıntılanması gerektiğinde `Sonuc<Olcum, HataKodu>` yazılır
ve `yaz` fonksiyonu dışındaki kod değişmez.

Bu tip, ilk derste konan sınır kuralının olgunlaşmış hâlidir. `oku` fonksiyonu ne bir
istisna atar ne de `null` döndürür; başarısızlığı **tipin bir üyesi** olarak taşır ve
çağıranın onu ele almasını derleyici zorunlu kılar. Ayırt edici birleşim burada bir hata
yönetimi aracına dönüşmüştür.

## Genelliğin Kötüye Kullanımı

Genellik her yerde iyileştirme sağlamaz. İki karşı örnek vardır.

**Tek kez geçen tip parametresi.** `function yazdir<T>(deger: T): void` imzasında `T`
yalnızca bir parametrede geçer ve hiçbir bağıntı kurmaz; `unknown` yazmak aynı işi daha
açık yapar. Genelliğin değeri, iki nokta arasında bir **bağ** kurmasındadır: girdi tipi
ile çıktı tipi, ya da iki parametre.

**Yalnızca dönüş tipinde geçen tip parametresi.** Bu, tip iddiasının gizlenmiş hâlidir:

```typescript
function tehlikeli<T>(ham: unknown): T {
  return ham as T;
}

const kimlik = tehlikeli<string>(42);
console.log(kimlik.toUpperCase());
```

Dosya tip denetiminden **geçer**, çalıştırıldığında ise:

```text
TypeError: kimlik.toUpperCase is not a function
```

Çağıran `T` olarak ne yazarsa yazsın derleyici kabul eder, çünkü gövdedeki `as T` yazımı
denetimi susturur. Bu imza, bir doğrulama vaat ediyor gibi görünüp hiçbir şey
doğrulamaz — `any` döndürmekten daha tehlikelidir, çünkü tip güvenli görünür.

Kural: **tip parametresi en az iki yerde geçmelidir.** Yalnızca dönüş tipinde geçiyorsa,
imza `unknown` döndürmeli ve çağıran daraltmayı kendisi yapmalıdır.

## Özet

- Tip parametresi, bir yapının biçimini kayıt tipinden bağımsız yazmayı sağlar ve
  `any` çözümünün aksine tip güvencesini korur.
- Tip argümanları çoğu zaman çağrı argümanlarından çıkarılır; çıkarım için parametrenin
  argüman listesinde geçmesi gerekir.
- Kısıt (`T extends K`), tip parametresi üzerinde işlem yapılabilmesini sağlar ve uymayan
  argümanları çağrı yerinde reddeder.
- `keyof T` alan adlarının birleşimini, `T[A]` indeksli erişim tipini verir; ikisi birlikte
  alan adına göre değişen dönüş tipleri kurar.
- Varsayılan tip parametresi yaygın durumu kısaltır; ayırt edici birleşimle kurulan sonuç
  tipi, başarısızlığı tipin bir üyesi olarak taşır.
- Tip parametresi en az iki yerde geçmelidir; yalnızca dönüş tipinde geçen bir parametre,
  gizlenmiş bir tip iddiasıdır.

## Sonraki Adım

Bu derste birkaç kez bir birleşim tipinin üzerinde sınama yapıldı ve derleyici tipi tek bir
üyeye indirdi. Bu indirgemenin kuralları henüz sıralanmadı: hangi sınamalar kanıt sayılır,
kanıt ne kadar uzağa taşınır, kendi yazdığınız doğrulama fonksiyonunun sonucu derleyiciye
nasıl bildirilir? Sonraki ders daraltmayı ayrıntılı ele alacak.
