JAVASCRIPT // TYPESCRIPTD::03 ORTA
18m READCOMPLETION: 90%ID::TS-101

TYPESCRIPT: GENERICS VE UTILITY TYPES

Tip sistemi, Generic fonksiyonlar, Utility Types ve Zod

TypeScript, JavaScript'e statik tip sistemi ekleyen bir üst kümedir. Derleme zamanında hataları yakalar, IDE desteğini güçlendirir ve büyük kod tabanlarında refactoring'i güvenli kılar. Tüm geçerli JavaScript kodu aynı zamanda geçerli TypeScript'tir.

Temel Tipler

// TYPESCRIPT //
// Primitifler
const ad: string = 'Ali';
const yas: number = 25;
const aktif: boolean = true;
const puan: null = null;
const tanimlanmamis: undefined = undefined;
 
// Diziler
const sayilar: number[] = [1, 2, 3];
const isimler: Array<string> = ['Ali', 'Ayşe'];
 
// Tuple — sabit uzunluk ve tip sırası
const koordinat: [number, number] = [41.0, 28.9];
const kayit: [string, number, boolean] = ['Ali', 25, true];
 
// Union tipler
type ID = string | number;
let kullaniciId: ID = 'abc-123';
kullaniciId = 42; // Her ikisi de geçerli
 
// Literal tipler
type Yon = 'kuzey' | 'guney' | 'dogu' | 'bati';
type HttpDurum = 200 | 201 | 400 | 401 | 403 | 404 | 500;

Interface ve Type

// TYPESCRIPT //
// Interface — nesne şeklini tanımlar, extend edilebilir
interface Kullanici {
  id: string;
  ad: string;
  email: string;
  yas?: number;       // opsiyonel
  readonly olusturuldu: Date; // salt okunur
}
 
// Interface genişletme
interface YoneticiKullanici extends Kullanici {
  yetkiler: string[];
  seviye: 1 | 2 | 3;
}
 
// Type alias — union, intersection ve karmaşık tipler için
type ApiCevap<T> = {
  veri: T;
  mesaj: string;
  basari: boolean;
};
 
// Intersection tipler
type TamKullanici = Kullanici & {
  profil: { avatar: string; biyografi: string };
};

Generics

// TYPESCRIPT //
// Generic fonksiyon
function ilkEleman<T>(dizi: T[]): T | undefined {
  return dizi[0];
}
 
const sayi = ilkEleman([1, 2, 3]);  // type: number | undefined
const metin = ilkEleman(['a', 'b']); // type: string | undefined
 
// Generic sınıf
class YigitDeposu<T> {
  private ogeler: T[] = [];
 
  it(oge: T): void {
    this.ogeler.push(oge);
  }
 
  cek(): T | undefined {
    return this.ogeler.pop();
  }
 
  get boyut(): number {
    return this.ogeler.length;
  }
}
 
const sayiYigiti = new YigitDeposu<number>();
sayiYigiti.it(1);
sayiYigiti.it(2);
console.log(sayiYigiti.cek()); // 2
 
// Generic kısıtlamalar
function anahtarAl<T, K extends keyof T>(nesne: T, anahtar: K): T[K] {
  return nesne[anahtar];
}
 
const kullanici = { ad: 'Ali', yas: 25 };
const ad = anahtarAl(kullanici, 'ad');  // string
const yas = anahtarAl(kullanici, 'yas'); // number
// anahtarAl(kullanici, 'sehir'); // HATA — 'sehir' kullanici'de yok

Utility Types

// TYPESCRIPT //
interface Makale {
  id: string;
  baslik: string;
  icerik: string;
  yazarId: string;
  yayinlandi: boolean;
  olusturuldu: Date;
}
 
// Partial — tüm alanları opsiyonel yapar
type MakaleGuncellemesi = Partial<Makale>;
// { id?: string; baslik?: string; ... }
 
// Required — tüm alanları zorunlu yapar
type ZorunluMakale = Required<Makale>;
 
// Pick — belirli alanları seçer
type MakaleOnizleme = Pick<Makale, 'id' | 'baslik' | 'yayinlandi'>;
 
// Omit — belirli alanları çıkarır
type YeniMakale = Omit<Makale, 'id' | 'olusturuldu'>;
 
// Record — anahtar-değer haritası
type RolIzinleri = Record<string, string[]>;
const izinler: RolIzinleri = {
  admin: ['okuma', 'yazma', 'silme'],
  editor: ['okuma', 'yazma'],
  okuyucu: ['okuma'],
};
 
// ReturnType — fonksiyonun dönüş tipini çıkar
async function kullaniciyiGetir(id: string) {
  return { id, ad: 'Ali', email: 'ali@test.com' };
}
type KullaniciBilgisi = Awaited<ReturnType<typeof kullaniciyiGetir>>;
// { id: string; ad: string; email: string }

Discriminated Unions

// TYPESCRIPT //
// Her varyantın ortak bir discriminant alanı var
type Sekil =
  | { tur: 'daire'; yaricap: number }
  | { tur: 'dikdortgen'; genislik: number; yukseklik: number }
  | { tur: 'ucgen'; taban: number; yukseklik: number };
 
function alan(sekil: Sekil): number {
  switch (sekil.tur) {
    case 'daire':
      return Math.PI * sekil.yaricap ** 2;
    case 'dikdortgen':
      return sekil.genislik * sekil.yukseklik;
    case 'ucgen':
      return (sekil.taban * sekil.yukseklik) / 2;
    // TypeScript: tüm durumlar kapsandı
  }
}
 
// API cevap modeli
type ApiSonuc<T> =
  | { durum: 'basarili'; veri: T }
  | { durum: 'hata'; mesaj: string; kod: number }
  | { durum: 'yukleniyor' };
 
function sonucuIsle<T>(sonuc: ApiSonuc<T>) {
  if (sonuc.durum === 'basarili') {
    // TypeScript: sonuc.veri kullanılabilir
    console.log(sonuc.veri);
  } else if (sonuc.durum === 'hata') {
    // TypeScript: sonuc.mesaj ve sonuc.kod kullanılabilir
    console.error(`${sonuc.kod}: ${sonuc.mesaj}`);
  }
}

Zod ile Runtime Validation

// TYPESCRIPT //
import { z } from 'zod';
 
// Schema tanımı
const KullaniciSema = z.object({
  id:    z.string().uuid(),
  ad:    z.string().min(2).max(100),
  email: z.string().email(),
  yas:   z.number().int().min(13).max(120).optional(),
  rol:   z.enum(['admin', 'editor', 'okuyucu']).default('okuyucu'),
});
 
// TypeScript tipi otomatik türetme
type Kullanici = z.infer<typeof KullaniciSema>;
 
// Validation
function kullaniciyiDogrula(ham: unknown): Kullanici {
  return KullaniciSema.parse(ham); // Hata fırlatır
}
 
// Güvenli versiyonu
function guvenliDogrula(ham: unknown) {
  const sonuc = KullaniciSema.safeParse(ham);
  if (!sonuc.success) {
    console.error(sonuc.error.flatten());
    return null;
  }
  return sonuc.data;
}

Pratik: Tip Güvenli API İstemcisi

// TYPESCRIPT //
type HttpMetot = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
 
interface IstekSecenekleri<B = unknown> {
  metot?: HttpMetot;
  govde?: B;
  basliklar?: Record<string, string>;
}
 
async function apiIstegi<T>(
  yol: string,
  secenekler: IstekSecenekleri = {}
): Promise<T> {
  const { metot = 'GET', govde, basliklar = {} } = secenekler;
 
  const cevap = await fetch(`/api${yol}`, {
    method: metot,
    headers: {
      'Content-Type': 'application/json',
      ...basliklar,
    },
    body: govde ? JSON.stringify(govde) : undefined,
  });
 
  if (!cevap.ok) {
    throw new Error(`API Hatası: ${cevap.status} ${cevap.statusText}`);
  }
 
  return cevap.json() as Promise<T>;
}
 
// Tip güvenli kullanım
interface Kullanici { id: string; ad: string; email: string; }
 
const kullanici = await apiIstegi<Kullanici>('/kullanicilar/123');
// kullanici.id — string olduğu kesin, IDE biliyor
 
const yeniKullanici = await apiIstegi<Kullanici>('/kullanicilar', {
  metot: 'POST',
  govde: { ad: 'Ali', email: 'ali@test.com' },
});

Sonuç

TypeScript'in Generics, Utility Types ve Discriminated Unions özellikleri, büyük ölçekli projelerde güvenli ve refactor-friendly kod yazmanıza olanak tanır. Bir sonraki konuda TypeScript ile React bileşen tiplemesini ele alacağız.