Fonksiyon Tipleri
Giriş — Fonksiyonları Zırhlamak
JavaScript'te fonksiyonlar birinci sınıf vatandaştır — değişkenlere atanır, parametre olarak geçilir, fonksiyonlardan döndürülür. Bu esneklik güçlü olmakla birlikte, bir fonksiyonun ne beklediğini ve ne döndürdüğünü bilmeyi zorlaştırır. "Bu fonksiyon kaç parametre alıyor? String mi number mı bekliyor? Ne döndürüyor? null dönebilir mi?" — bu soruların cevabı JavaScript'te ancak kaynak kodunu okuyarak bulunur.
TypeScript, fonksiyonlara tip zırhı giyer: hangi parametreleri kabul ettiğini, ne döndürdüğünü, hangi durumda ne davrandığını — hepsini derleme zamanında garanti eder. Bu derste fonksiyon tiplerinin derinliklerine dalacağız.
Analoji: Bir restoranın menüsünü düşünün. Menüde her yemeğin adı, malzemeleri ve fiyatı yazar. Mutfağa sipariş verirken, menüde olmayan bir yemek isteyemezsiniz; garson sizi uyarır. TypeScript'in fonksiyon tipleri, o menüdür — fonksiyonun neyi kabul ettiğini ve neyi sunacağını önceden bildirir. Yanlış sipariş vermeye çalıştığınızda derleyici (garson) sizi durdurur.
Parametre ve Dönüş Tipleri
Temel Sözdizimi
// Parametre tipleri + dönüş tipi
function topla(a: number, b: number): number {
return a + b;
}
topla(5, 3); // ✅ → 8
// topla("5", 3); // ❌ Error: Argument of type 'string' is not assignable to parameter of type 'number'
// topla(5); // ❌ Error: Expected 2 arguments, but got 1
// topla(5, 3, 1); // ❌ Error: Expected 2 arguments, but got 3
// Arrow function ile
const carp = (a: number, b: number): number => a * b;
// Dönüş tipi çıkarımı — genellikle yazmaya gerek yok
function selamla(isim: string) {
return `Merhaba, ${isim}!`; // TypeScript: dönüş tipi string
}
// Ama public API'lerde açıkça yazmak iyi pratik:
function kullaniciBul(id: number): Kullanici | null {
// Dönüş tipi hem belgeleme hem de güvenlik sağlar
// İç implementasyon değişse bile dönüş tipi garanti
}Opsiyonel Parametreler
// ? ile opsiyonel parametre
function log(mesaj: string, seviye?: string): void {
// seviye: string | undefined
const logSeviye = seviye ?? "INFO";
console.log(`[${logSeviye}] ${mesaj}`);
}
log("Uygulama başladı"); // [INFO] Uygulama başladı
log("Bağlantı koptu", "ERROR"); // [ERROR] Bağlantı koptu
// ⚠️ Opsiyonel parametreler zorunlu olanlardan SONRA gelmelidir
// function hatali(a?: number, b: number) {} // ❌ Error!Varsayılan Değerler
// Varsayılan değer — opsiyonel parametre gibi davranır ama undefined yerine varsayılan kullanılır
function sayfa(
icerik: string[],
sayfaNo: number = 1,
sayfaBoyutu: number = 10
): string[] {
const baslangic = (sayfaNo - 1) * sayfaBoyutu;
return icerik.slice(baslangic, baslangic + sayfaBoyutu);
}
sayfa(urunler); // sayfaNo=1, sayfaBoyutu=10
sayfa(urunler, 2); // sayfaNo=2, sayfaBoyutu=10
sayfa(urunler, 3, 20); // sayfaNo=3, sayfaBoyutu=20
// Varsayılan değerden tip çıkarımı yapılır — tip belirtmeye gerek yok
function baglan(host = "localhost", port = 3000) {
// host: string, port: number — otomatik çıkarım
console.log(`${host}:${port}`);
}Rest Parametreler
// Rest parametre — sonsuz sayıda argüman
function toplam(...sayilar: number[]): number {
return sayilar.reduce((acc, n) => acc + n, 0);
}
toplam(1, 2, 3); // 6
toplam(10, 20, 30, 40); // 100
toplam(); // 0
// Normal + rest parametre
function ekipOlustur(lider: string, ...uyeler: string[]): void {
console.log(`Lider: ${lider}`);
console.log(`Üyeler: ${uyeler.join(", ")}`);
}
ekipOlustur("Ali", "Ayşe", "Mehmet", "Zeynep");
// Tuple ile rest — belirli yapıda rest
function veriEkle(...args: [tablo: string, veri: object, sessiz?: boolean]): void {
const [tablo, veri, sessiz = false] = args;
if (!sessiz) console.log(`${tablo} tablosuna ekleniyor...`);
// veriTabani.ekle(tablo, veri);
}
veriEkle("kullanicilar", { isim: "Ali" }); // sessiz=false
veriEkle("loglar", { mesaj: "test" }, true); // sessiz=trueFonksiyon Tipi İfadeleri
Fonksiyon tiplerini değişkenlere, parametrelere ve dönüş tiplerine atamak için fonksiyon tipi ifadeleri kullanılır.
// Fonksiyon tipi tanımı
type Hesaplama = (a: number, b: number) => number;
// Bu tipe uyan fonksiyonlar
const topla: Hesaplama = (a, b) => a + b;
const carp: Hesaplama = (a, b) => a * b;
const cikar: Hesaplama = (a, b) => a - b;
// Parametre olarak fonksiyon tipi
function hesapYap(a: number, b: number, islem: Hesaplama): number {
return islem(a, b);
}
console.log(hesapYap(10, 5, topla)); // 15
console.log(hesapYap(10, 5, carp)); // 50
console.log(hesapYap(10, 5, cikar)); // 5
// ❌ Yanlış imza — tip uyumsuz
// const hatali: Hesaplama = (a: string) => a.length;
// Error: Type '(a: string) => number' is not assignable to type 'Hesaplama'Callback Tipleri
// Event handler tipi
type OlayHandler = (olay: { tip: string; hedef: string }) => void;
// Asenkron callback
type VeriCallback<T> = (hata: Error | null, sonuc: T | null) => void;
// Fonksiyon döndüren fonksiyon (Higher-Order Function)
type Karsilastirici<T> = (a: T, b: T) => number;
function siralamaylaGetir<T>(
veri: T[],
karsilastir: Karsilastirici<T>
): T[] {
return [...veri].sort(karsilastir);
}
interface Urun {
isim: string;
fiyat: number;
}
const urunler: Urun[] = [
{ isim: "Tablet", fiyat: 8000 },
{ isim: "Laptop", fiyat: 25000 },
{ isim: "Kulaklık", fiyat: 500 },
];
// Fiyata göre sırala
const fiyatSirali = siralamaylaGetir(urunler, (a, b) => a.fiyat - b.fiyat);
console.log(fiyatSirali.map(u => `${u.isim}: ${u.fiyat}₺`));
// ["Kulaklık: 500₺", "Tablet: 8000₺", "Laptop: 25000₺"]
// İsme göre sırala
const isimSirali = siralamaylaGetir(urunler, (a, b) => a.isim.localeCompare(b.isim));Call Signature (Interface ile Fonksiyon Tipi)
// Interface ile fonksiyon tipi — ek özellikler eklenebilir
interface FormatliFonksiyon {
(deger: number): string; // Call signature
hassasiyet: number; // Ek özellik
birim: string; // Ek özellik
}
// Implementasyon
const paraFormatla: FormatliFonksiyon = Object.assign(
(deger: number): string => {
return `${deger.toFixed(paraFormatla.hassasiyet)} ${paraFormatla.birim}`;
},
{
hassasiyet: 2,
birim: "₺"
}
);
console.log(paraFormatla(1234.5)); // "1234.50 ₺"
paraFormatla.birim = "$";
console.log(paraFormatla(1234.5)); // "1234.50 $"Function Overloads (Fonksiyon Aşırı Yükleme)
Overload, aynı fonksiyonun farklı parametre kombinasyonlarında farklı dönüş tipleri döndürmesini sağlar. Bu, özellikle bir fonksiyonun girdi tipine göre çıktı tipinin değiştiği durumlarda tip güvenliğini artırır.
// Problem: Union kullanınca dönüş tipi de union olur
function degerIsle(deger: string | number): string | number {
if (typeof deger === "string") {
return deger.toUpperCase(); // string döndürüyor
}
return deger * 2; // number döndürüyor
}
const sonuc = degerIsle("merhaba"); // string | number — ama biz string olduğunu biliyoruz!
// sonuc.toUpperCase(); // ❌ Error: Property 'toUpperCase' does not exist on type 'string | number'
// ✅ Çözüm: Function overloads
function degerIsleV2(deger: string): string; // Overload 1
function degerIsleV2(deger: number): number; // Overload 2
function degerIsleV2(deger: string | number): string | number { // İmplementasyon
if (typeof deger === "string") {
return deger.toUpperCase();
}
return deger * 2;
}
const metin = degerIsleV2("merhaba"); // string — kesin!
const sayi = degerIsleV2(42); // number — kesin!
metin.toUpperCase(); // ✅ Artık çalışır
sayi.toFixed(2); // ✅ Artık çalışırOverload Kuralları
// 1. Overload imzaları (signature) — dışarıdan görünen
// 2. İmplementasyon imzası — tüm overload'ları karşılamalı
// 3. İmplementasyon imzası dışarıdan çağrılamaz
// Örnek: DOM querySelector'ın tip-güvenli versiyonu
function sec(selector: "#email"): HTMLInputElement;
function sec(selector: "#baslik"): HTMLHeadingElement;
function sec(selector: string): HTMLElement;
function sec(selector: string): HTMLElement {
return document.querySelector(selector) as HTMLElement;
}
const email = sec("#email"); // HTMLInputElement
const baslik = sec("#baslik"); // HTMLHeadingElement
const diger = sec(".kart"); // HTMLElement
email.value; // ✅ HTMLInputElement'e özgü
baslik.textContent; // ✅ HTMLHeadingElement'e özgü
// Daha karmaşık overload
function olustur(tip: "kullanici", veri: { isim: string; email: string }): Kullanici;
function olustur(tip: "urun", veri: { isim: string; fiyat: number }): Urun;
function olustur(tip: string, veri: object): unknown {
if (tip === "kullanici") {
return { id: Date.now(), ...(veri as any), aktif: true };
}
if (tip === "urun") {
return { id: Date.now(), ...(veri as any), stok: 0 };
}
throw new Error(`Bilinmeyen tip: ${tip}`);
}
interface Kullanici { id: number; isim: string; email: string; aktif: boolean; }
interface Urun { id: number; isim: string; fiyat: number; stok: number; }
const user = olustur("kullanici", { isim: "Ali", email: "ali@test.com" });
// user: Kullanici — tip güvenli!
console.log(user.aktif); // ✅
const product = olustur("urun", { isim: "Laptop", fiyat: 25000 });
// product: Urun — tip güvenli!
console.log(product.stok); // ✅⚠️ Dikkat: Overload'ları karmaşıklaştırmaktan kaçının. Çoğu durumda generic fonksiyonlar veya union type + narrowing daha temiz bir çözüm sunar. Overload, özellikle parametre tipi ile dönüş tipi arasında doğrudan bağlantı olduğunda en faydalıdır.
Overload vs Generic — Ne Zaman Hangisi?
// Overload: Farklı parametre tipleri → farklı dönüş tipleri
function parse(deger: string): object;
function parse(deger: Buffer): object;
function parse(deger: string | Buffer): object { /* ... */ return {}; }
// Generic: Aynı mantık, farklı tipler — girdi tipi ile çıktı tipi ilişkili
function sarma<T>(deger: T): { deger: T; zaman: number } {
return { deger, zaman: Date.now() };
}
// Genel kural:
// - Parametre sayısı veya yapısı değişiyorsa → overload
// - Aynı yapı, farklı tiplerle çalışıyorsa → generic
// - Basit tip dönüşümü → generic + conditional typeGeneric Fonksiyonlar — Derinlemesine
Önceki derste generics'e giriş yaptık. Şimdi fonksiyon özelinde daha derinleşelim.
Birden Fazla Tip Parametresi
// İki tip parametresi
function haritalaDonustur<Girdi, Cikti>(
dizi: Girdi[],
donusturucu: (eleman: Girdi) => Cikti
): Cikti[] {
return dizi.map(donusturucu);
}
const sayilar = [1, 2, 3, 4, 5];
const metinler = haritalaDonustur(sayilar, n => n.toString());
// metinler: string[] — tip otomatik çıkarıldı
const kullanicilar = [
{ isim: "Ali", yas: 28 },
{ isim: "Ayşe", yas: 32 },
];
const isimler = haritalaDonustur(kullanicilar, k => k.isim);
// isimler: string[]
// Nesne dönüşümü
const ozet = haritalaDonustur(kullanicilar, k => ({
etiket: `${k.isim} (${k.yas})`,
yetiskin: k.yas >= 18
}));
// ozet: { etiket: string; yetiskin: boolean }[]Constraint ile Generic
// T "length" özelliğine sahip olmalı
interface Uzunluklu {
length: number;
}
function enUzununu<T extends Uzunluklu>(a: T, b: T): T {
return a.length >= b.length ? a : b;
}
enUzununu("merhaba", "dünya"); // ✅ string'de length var
enUzununu([1, 2, 3], [1, 2, 3, 4]); // ✅ array'de length var
// enUzununu(42, 100); // ❌ number'da length yok
// keyof ile güvenli property erişimi
function gruplaBy<T, K extends keyof T>(
dizi: T[],
anahtar: K
): Map<T[K], T[]> {
const harita = new Map<T[K], T[]>();
for (const eleman of dizi) {
const grupAnahtari = eleman[anahtar];
const mevcutGrup = harita.get(grupAnahtari) ?? [];
mevcutGrup.push(eleman);
harita.set(grupAnahtari, mevcutGrup);
}
return harita;
}
interface Ogrenci {
isim: string;
sinif: string;
not: number;
}
const ogrenciler: Ogrenci[] = [
{ isim: "Ali", sinif: "10-A", not: 85 },
{ isim: "Ayşe", sinif: "10-B", not: 92 },
{ isim: "Mehmet", sinif: "10-A", not: 78 },
{ isim: "Zeynep", sinif: "10-B", not: 95 },
];
const sinifGruplari = gruplaBy(ogrenciler, "sinif");
// Map<string, Ogrenci[]>
// "10-A" → [Ali, Mehmet]
// "10-B" → [Ayşe, Zeynep]
// ❌ Olmayan anahtar
// gruplaBy(ogrenciler, "adres"); // Error: "adres" is not assignable to "isim" | "sinif" | "not"Generic ile Default Tip
// Varsayılan tip parametresi
interface FetchAyar<T = unknown> {
url: string;
method?: "GET" | "POST" | "PUT" | "DELETE";
body?: T;
headers?: Record<string, string>;
}
// T belirtilmezse unknown kullanılır
const getAyar: FetchAyar = {
url: "/api/kullanicilar",
method: "GET"
};
// T belirtilirse o tip kullanılır
const postAyar: FetchAyar<{ isim: string; email: string }> = {
url: "/api/kullanicilar",
method: "POST",
body: { isim: "Ali", email: "ali@test.com" }
};Type Guards (Tip Koruyucuları)
Type guard, bir değişkenin tipini çalışma zamanında kontrol edip TypeScript'e bildiren mekanizmadır. Narrowing'in resmi ve güçlü halidir.
typeof Guard
function birlestir(a: string | number, b: string | number): string | number {
// typeof ile tip kontrolü
if (typeof a === "string" || typeof b === "string") {
return `${a}${b}`; // String birleştirme
}
return a + b; // Sayı toplama — TypeScript ikisinin de number olduğunu bilir
}
console.log(birlestir("Merhaba ", "Dünya")); // "Merhaba Dünya"
console.log(birlestir(10, 20)); // 30
console.log(birlestir("Sayı: ", 42)); // "Sayı: 42"instanceof Guard
class Araba {
sur() { console.log("Araba sürülüyor 🚗"); }
}
class Bisiklet {
pedalla() { console.log("Pedal çevriliyor 🚴"); }
}
function hareketeGec(arac: Araba | Bisiklet): void {
if (arac instanceof Araba) {
arac.sur(); // ✅ TypeScript: Araba
} else {
arac.pedalla(); // ✅ TypeScript: Bisiklet
}
}
// Hata sınıflarında
function hataIsle(hata: unknown): string {
if (hata instanceof TypeError) {
return `Tip hatası: ${hata.message}`;
}
if (hata instanceof RangeError) {
return `Aralık hatası: ${hata.message}`;
}
if (hata instanceof Error) {
return `Genel hata: ${hata.message}`;
}
return `Bilinmeyen hata: ${String(hata)}`;
}in Operator Guard
interface Kus {
kanatAcikligi: number;
uc(): void;
}
interface Balik {
yuzgecUzunlugu: number;
yuz(): void;
}
function hareket(hayvan: Kus | Balik): void {
if ("kanatAcikligi" in hayvan) {
hayvan.uc(); // ✅ TypeScript: Kus
} else {
hayvan.yuz(); // ✅ TypeScript: Balik
}
}Custom Type Guard (Kullanıcı Tanımlı)
En güçlü type guard yöntemidir. parametre is Tip sözdizimi ile kendi guard fonksiyonlarınızı yazabilirsiniz:
// "x is Y" sözdizimi — custom type guard
interface Kullanici {
tip: "kullanici";
isim: string;
email: string;
}
interface Admin {
tip: "admin";
isim: string;
email: string;
yetkiler: string[];
}
type Kisi = Kullanici | Admin;
// Custom type guard fonksiyonu
function adminMi(kisi: Kisi): kisi is Admin {
return kisi.tip === "admin";
}
function karsilama(kisi: Kisi): string {
if (adminMi(kisi)) {
// TypeScript biliyor: kisi → Admin
return `Admin ${kisi.isim} — Yetkiler: ${kisi.yetkiler.join(", ")}`;
}
// TypeScript biliyor: kisi → Kullanici
return `Kullanıcı ${kisi.isim}`;
}
// Dizi filtrelemede type guard
const kisiler: Kisi[] = [
{ tip: "kullanici", isim: "Ali", email: "ali@test.com" },
{ tip: "admin", isim: "Ayşe", email: "ayse@test.com", yetkiler: ["yazma", "silme"] },
{ tip: "kullanici", isim: "Mehmet", email: "mehmet@test.com" },
{ tip: "admin", isim: "Zeynep", email: "zeynep@test.com", yetkiler: ["okuma"] },
];
// filter ile type guard — dönüş tipi Admin[]
const adminler = kisiler.filter(adminMi);
// adminler: Admin[] — her elemanın yetkiler özelliği var!
adminler.forEach(admin => {
console.log(`${admin.isim}: ${admin.yetkiler.join(", ")}`);
});Discriminated Union (Ayrımcı Birleşim)
Ortak bir literal özellik (genellikle type veya kind) ile union tiplerini ayırt etme kalıbıdır. TypeScript bunu otomatik olarak tanır:
// Her tip, "tur" özelliğiyle ayırt edilir
interface Daire {
tur: "daire";
yaricap: number;
}
interface Kare {
tur: "kare";
kenar: number;
}
interface Ucgen {
tur: "ucgen";
taban: number;
yukseklik: number;
}
type Sekil = Daire | Kare | Ucgen;
function alanHesapla(sekil: Sekil): number {
switch (sekil.tur) {
case "daire":
// TypeScript: sekil → Daire
return Math.PI * sekil.yaricap ** 2;
case "kare":
// TypeScript: sekil → Kare
return sekil.kenar ** 2;
case "ucgen":
// TypeScript: sekil → Ucgen
return (sekil.taban * sekil.yukseklik) / 2;
default:
// Exhaustiveness check — tüm durumlar ele alındı mı?
const _asla: never = sekil;
throw new Error(`Bilinmeyen şekil: ${JSON.stringify(_asla)}`);
}
}
console.log(alanHesapla({ tur: "daire", yaricap: 5 })); // 78.54
console.log(alanHesapla({ tur: "kare", kenar: 4 })); // 16
console.log(alanHesapla({ tur: "ucgen", taban: 6, yukseklik: 3 })); // 9💡 İpucu: Discriminated union, TypeScript'te en yaygın ve en güçlü tip daraltma kalıbıdır. Özellikle state management, API yanıtları, hata yönetimi gibi senaryolarda kullanılır. Redux action'ları, React useReducer, API response tipleri — hepsinde bu kalıbı görürsünüz.
Gerçek Dünya Örneği: Tip-Güvenli Event Emitter
Bu örnek, bu derste öğrendiğimiz tüm kavramları bir arada kullanır:
// Event haritası — her event adı için parametre tipi
interface UygulamaEventleri {
"kullanici:giris": { kullaniciId: number; zaman: Date };
"kullanici:cikis": { kullaniciId: number };
"sepet:eklendi": { urunId: number; adet: number; fiyat: number };
"sepet:guncellendi": { urunId: number; yeniAdet: number };
"sepet:bos": undefined;
"hata": { kod: number; mesaj: string; detay?: string };
}
// Tip-güvenli event emitter
class EventYayinici<Eventler extends Record<string, unknown>> {
private dinleyiciler = new Map<
keyof Eventler,
Set<(veri: any) => void>
>();
// Overload: veri alan event'ler vs almayan event'ler
dinle<K extends keyof Eventler>(
event: K,
handler: Eventler[K] extends undefined
? () => void
: (veri: Eventler[K]) => void
): () => void {
if (!this.dinleyiciler.has(event)) {
this.dinleyiciler.set(event, new Set());
}
this.dinleyiciler.get(event)!.add(handler as any);
// Kaldırma fonksiyonu döndür
return () => {
this.dinleyiciler.get(event)?.delete(handler as any);
};
}
// Event yayınla — tip güvenli
yayinla<K extends keyof Eventler>(
...args: Eventler[K] extends undefined
? [event: K]
: [event: K, veri: Eventler[K]]
): void {
const [event, veri] = args;
const handlers = this.dinleyiciler.get(event);
if (handlers) {
handlers.forEach(handler => handler(veri));
}
}
}
// Kullanım
const bus = new EventYayinici<UygulamaEventleri>();
// ✅ Tip-güvenli dinleme
const kaldir = bus.dinle("kullanici:giris", (veri) => {
console.log(`Kullanıcı #${veri.kullaniciId} giriş yaptı`);
// veri.kullaniciId → number ✅
// veri.zaman → Date ✅
});
bus.dinle("sepet:eklendi", (veri) => {
const toplam = veri.adet * veri.fiyat;
console.log(`Sepete eklendi: ${toplam}₺`);
});
bus.dinle("hata", (veri) => {
console.error(`Hata ${veri.kod}: ${veri.mesaj}`);
if (veri.detay) console.error(`Detay: ${veri.detay}`);
});
// ✅ Tip-güvenli yayınlama
bus.yayinla("kullanici:giris", {
kullaniciId: 42,
zaman: new Date()
});
bus.yayinla("sepet:eklendi", {
urunId: 1,
adet: 2,
fiyat: 49.99
});
// ❌ Yanlış veri yapısı → derleme hatası
// bus.yayinla("kullanici:giris", { id: 42 });
// Error: 'kullaniciId' is missing
// ❌ Olmayan event → derleme hatası
// bus.yayinla("bilinmeyen:event", {});
// Error: '"bilinmeyen:event"' is not assignable to type
// Listener'ı kaldır
kaldir(); // Artık "kullanici:giris" dinlenmiyorBu örnekte kullanılan kavramlar:
Generic class (
EventYayinici<Eventler>) — farklı event yapıları için yeniden kullanılabilir`keyof` — event isimlerini tip güvenli olarak kısıtlar
Conditional type (
Eventler[K] extends undefined ? ...) — veri alan/almayan event'leri ayırırFonksiyon tipi parametreleri — handler'ların doğru tipte parametre almasını garanti eder
Rest tuple parametre —
yayinlafonksiyonunun esnek ama tip-güvenli API'si
Yaygın Hatalar ve En İyi Pratikler
Hata 1: Aşırı Overload
// ❌ Çok fazla overload — okunması zor
function formatla(deger: string): string;
function formatla(deger: number): string;
function formatla(deger: boolean): string;
function formatla(deger: Date): string;
function formatla(deger: any): string { /* ... */ return ""; }
// ✅ Union veya generic ile daha temiz
function formatla(deger: string | number | boolean | Date): string {
if (deger instanceof Date) return deger.toISOString();
return String(deger);
}Hata 2: any Kullanarak Type Guard Atlamak
// ❌ as any ile type guard'ı bypass etmek
function tehlikeli(veri: unknown) {
(veri as any).metot(); // 💥 Runtime hatası!
}
// ✅ Doğru narrowing
function guvenli(veri: unknown) {
if (typeof veri === "object" && veri !== null && "metot" in veri) {
(veri as { metot: () => void }).metot(); // ✅ Kontrol edildi
}
}Hata 3: Return Tipini Eksik Bırakmak (Public API)
// ❌ İç fonksiyonlarda sorun olmaz ama public API'de riskli
export function veriGetir(id: number) {
// İmplementasyon değişirse dönüş tipi de değişir — bağımlı kod kırılabilir
return fetch(`/api/${id}`).then(r => r.json());
}
// ✅ Açık dönüş tipi — sözleşme
export function veriGetir(id: number): Promise<ApiYanit<Kullanici>> {
return fetch(`/api/${id}`).then(r => r.json());
// İmplementasyon değişse bile dönüş tipi garanti
}Özet
🔹 Parametre tipleri zorunludur, dönüş tipleri çıkarılabilir ama public API'lerde açıkça yazmak en iyi pratiktir. Opsiyonel (
?), varsayılan (= değer) ve rest (...args) parametreler desteklenir.🔹 Fonksiyon tipi ifadeleri (
type Fn = (a: number) => string) callback'leri, event handler'ları ve higher-order function'ları tiplemek için kullanılır.🔹 Function overloads farklı parametre kombinasyonlarında farklı dönüş tipleri garanti eder. Basit durumlar için generic veya union tercih edin; overload'ı parametre-dönüş bağlantısı olduğunda kullanın.
🔹 Generic fonksiyonlar (
<T>) tek tanımla birden fazla tipte çalışır.extendsile kısıtlama,keyofile anahtar güvenliği, varsayılan tip (<T = unknown>) desteklenir.🔹 Type guard'lar (
typeof,instanceof,in, customis) union tiplerini çalışma zamanında daraltır. Discriminated union (tur: "daire") en güçlü ve yaygın kalıptır.🔹 Custom type guard (
fonksiyon(x): x is Tip) kendi tip kontrol fonksiyonlarınızı yazmanızı sağlar —filter()gibi dizi metotlarıyla birlikte güçlü tip daraltma yapar.
AI Asistan
Sorularını yanıtlamaya hazır