Skip to content

TypeScript Mastery Guide — Tip Güvenli JavaScript (Type-Safe JavaScript) (EN + TR)

Complete English + Turkish reference guide for TypeScript: type system, generics, utility types, React/Node.js integration, and best practices.
(TypeScript için kapsamlı rehber: tip sistemi, generics, utility types, React/Node.js entegrasyonu ve en iyi uygulamalar.)

Ne Zaman TypeScript? (When to Use TypeScript?)

İdeal: ✅ Orta-büyük projeler, ekip çalışmaları, uzun ömürlü kod tabanları (medium-large projects, team collaboration, long-lived codebases)
Dikkat: ⚠️ Öğrenme eğrisi, tip sistemi karmaşıklığı, ek derleme adımı (learning curve, type system complexity, extra compilation step)
Uygun değil: ❌ Hızlı script/prototip, tek kullanımlık araçlar, çok küçük projeler (quick scripts/prototypes, disposable tools, very small projects)

Önerilen yığın: TypeScript + React/Next.js (frontend) veya TypeScript + Node.js/Express (backend)
Alternatifler: Flow (Meta, azalan topluluk), JSDoc (sıfır build adımı, sınırlı tip sistemi)

1) TypeScript Nedir? (What is TypeScript?)

TypeScript = JavaScript + Static Types.
Microsoft tarafından geliştirildi, JS'e derlenir. Her geçerli JS dosyası aynı zamanda geçerli TS dosyasıdır.
(TypeScript, JavaScript'in üstüne statik tip sistemi ekler. Derlendiğinde saf JS üretir.)

Neden TypeScript? (Why TypeScript?)

  • Hataları derleme zamanında yakalar (catches bugs at compile time)
  • IDE desteği: otomatik tamamlama, refactoring (better IntelliSense)
  • Büyük projelerde güvenli refactoring (safe refactoring in large codebases)
  • Dokümantasyon görevi görür (types serve as documentation)

JS vs TS Karşılaştırma (Comparison):

Özellik (Feature)JavaScriptTypeScript
Tip Sistemi (Type System)Dinamik (dynamic)Statik (static)
Derleme (Compilation)Gerekmeztsc ile derlenir
Hata Yakalama (Error Catching)RuntimeCompile-time
Dosya Uzantısı (File Extension).js.ts / .tsx
Öğrenme Eğrisi (Learning Curve)Düşük (low)Orta (medium)

Kurulum (Installation):

bash
# Global kurulum (global install)
npm install -g typescript

# Proje bazlı kurulum (recommended)
npm install --save-dev typescript

# Versiyon kontrol
npx tsc --version

# Proje başlatma — tsconfig.json oluşturur
npx tsc --init

Temel tsconfig.json:

json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Derleme ve Çalıştırma (Compiling and Running):

bash
# Tek dosya derleme (single file compilation)
npx tsc app.ts

# Proje derleme (tsconfig.json kullanır)
npx tsc

# Watch mode — dosya değişikliklerini izler (watches file changes)
npx tsc --watch

# ts-node ile doğrudan çalıştır (geliştirme için)
npx ts-node app.ts

Summary: TypeScript, JavaScript'in tip güvenli versiyonudur. npm i -D typescript ile başla, npx tsc --init ile yapılandır.


2) Temel Tipler (Basic Types)

Primitives (Temel Tipler):

typescript
// String
let isim: string = "Fahri";

// Number (tam sayı ve ondalık aynı tip)
let yas: number = 28;
let fiyat: number = 99.99;

// Boolean
let aktif: boolean = true;

// Template literal type
type Renk = "kirmizi" | "mavi" | "yesil";
let secilen: Renk = "mavi";

Array (Dizi):

typescript
// İki yazım şekli — ikisi de aynı (two syntax forms — both equivalent)
let sayilar: number[] = [1, 2, 3];
let isimler: Array<string> = ["Ali", "Veli"];

// Readonly array — değiştirilemez dizi (immutable array)
let sabitler: readonly number[] = [10, 20, 30];
// sabitler.push(40); // HATA: readonly

Tuple (Demet):

typescript
// Sabit uzunluk ve sıra, her eleman farklı tip olabilir
// (Fixed length and order, each element can be a different type)
let kisi: [string, number] = ["Fahri", 28];

// Named tuple (isimli demet)
type KullaniciKayit = [isim: string, yas: number, aktif: boolean];
let kayit: KullaniciKayit = ["Ali", 30, true];

// Readonly tuple
let koordinat: readonly [number, number] = [41.01, 28.97];

Enum:

typescript
// Numeric enum (varsayılan 0'dan başlar — defaults start from 0)
enum Durum {
  Beklemede,    // 0
  Onaylandi,    // 1
  Reddedildi    // 2
}
let siparis: Durum = Durum.Onaylandi;

// String enum (tercih edilen — daha okunabilir) (preferred — more readable)
enum Rol {
  Admin = "ADMIN",
  Kullanici = "USER",
  Moderator = "MOD"
}

// const enum — derleme zamanında satır içi (inlined at compile time)
const enum Yon {
  Yukari = "UP",
  Asagi = "DOWN"
}

any, unknown, void, never:

typescript
// any — tip kontrolünü devre dışı bırakır (KAÇINILMALI)
// (disables type checking — SHOULD BE AVOIDED)
let hersey: any = "test";
hersey = 42;        // hata yok, tehlikeli
hersey.foo.bar;     // hata yok, runtime'da patlar

// unknown — güvenli any, kullanmadan önce kontrol gerekir
// (safe any — requires type checking before use)
let belirsiz: unknown = getExternalData();
// belirsiz.toUpperCase(); // HATA: önce kontrol et
if (typeof belirsiz === "string") {
  belirsiz.toUpperCase(); // OK, artık string olduğu biliniyor
}

// void — fonksiyon değer döndürmez (function returns no value)
function logla(mesaj: string): void {
  console.log(mesaj);
}

// never — asla tamamlanmayan veya ulaşılamaz kod
// (never completes or unreachable code)
function hataFirlat(mesaj: string): never {
  throw new Error(mesaj);
}

function sonsuzDongu(): never {
  while (true) {}
}

null ve undefined:

typescript
// strictNullChecks açıkken (ki açık olmalı)
// (when strictNullChecks is enabled — which it should be)
let deger: string | null = null;
let tanimsiz: string | undefined = undefined;

// Optional chaining — güvenli erişim (safe access)
let uzunluk = deger?.length; // null ise undefined döner

// Nullish coalescing — null/undefined ise varsayılan değer
// (default value if null/undefined)
let sonuc = deger ?? "varsayilan";

// Non-null assertion (dikkatli kullan — use carefully)
let kesinVar: string = deger!; // "ben biliyorum null değil" demek

Summary: unknown > any tercih et. strictNullChecks açık tut. Enum yerine union literal type'ı düşün.


3) Type Aliases & Interfaces (Tip Takma Adları ve Arayüzler)

Type Alias — type anahtar kelimesi (keyword):

typescript
// Basit tip takma adı (simple type alias)
type ID = string | number;

// Obje tipi (object type)
type Kullanici = {
  id: ID;
  isim: string;
  email: string;
  yas?: number; // optional — opsiyonel alan
};

// Fonksiyon tipi (function type)
type Karsilastirici<T> = (a: T, b: T) => number;

// Union type alias
type Sonuc = "basarili" | "basarisiz" | "beklemede";

// Mapped type (ileri seviye — advanced)
type ReadonlyKullanici = Readonly<Kullanici>;

Interface — interface anahtar kelimesi:

typescript
interface Urun {
  id: number;
  ad: string;
  fiyat: number;
  stokta: boolean;
}

// Extends — genişletme (kalıtım) (inheritance)
interface DigitalUrun extends Urun {
  indirmeLinki: string;
  dosyaBoyutu: number;
}

// Implements — sınıfla kullanım (usage with class)
class Kitap implements Urun {
  constructor(
    public id: number,
    public ad: string,
    public fiyat: number,
    public stokta: boolean,
    public sayfaSayisi: number
  ) {}
}

Type vs Interface — Ne Zaman Hangisi? (When to Use Which?)

Özellik (Feature)typeinterface
Obje tanımla (Define object)EvetEvet
Union/IntersectionEvetHayır
extends& ileextends ile
Declaration mergingHayırEvet
Computed propertiesEvetHayır
Primitif aliasEvetHayır
typescript
// INTERFACE — declaration merging (otomatik birleştirme — auto-merging)
interface Pencere {
  baslik: string;
}
interface Pencere {
  genislik: number;
}
// Pencere artık { baslik: string; genislik: number; }

// TYPE — intersection ile genişletme (extending with intersection)
type Hayvan = { isim: string };
type Kedi = Hayvan & { miyavlar: boolean };

// TYPE — union (interface ile yapılamaz — cannot be done with interface)
type StringVeyaSayi = string | number;

Pratik Kural (Practical Rule):

  • API/library tanımlarında interface kullan (genişletilebilir — extensible)
  • Union, intersection, mapped type için type kullan
  • Tutarlı ol: projede birini seç ve devam et (be consistent)

Summary: Interface obje şekilleri için, type her şey için. Çoğu projede type yeterli.


4) Fonksiyonlar (Functions)

Parametre ve Dönüş Tipleri (Parameter and Return Types):

typescript
// Temel fonksiyon (basic function)
function topla(a: number, b: number): number {
  return a + b;
}

// Arrow function
const carp = (a: number, b: number): number => a * b;

// Dönüş tipi genellikle çıkarılır (type inference)
// ama açıkça yazmak daha iyi pratiktir (but explicit is better practice)
const selamla = (isim: string) => `Merhaba ${isim}`;
// TypeScript dönüş tipini string olarak çıkarır

Optional ve Default Parametreler:

typescript
// Optional parametre — ? ile işaretlenir (marked with ?)
function kullaniciOlustur(
  isim: string,
  email: string,
  yas?: number           // opsiyonel, undefined olabilir
): Kullanici {
  return { id: Date.now(), isim, email, yas };
}

// Default değer (default value)
function sayfalama(
  sayfa: number = 1,
  limit: number = 10
): { sayfa: number; limit: number } {
  return { sayfa, limit };
}

// Rest parametreleri (rest parameters)
function toplam(...sayilar: number[]): number {
  return sayilar.reduce((acc, n) => acc + n, 0);
}
toplam(1, 2, 3, 4); // 10

Function Overloads (Fonksiyon Aşırı Yüklemesi):

typescript
// Overload imzaları (overload signatures)
function formatla(deger: string): string;
function formatla(deger: number): string;
function formatla(deger: string | number): string {
  if (typeof deger === "string") {
    return deger.trim().toLowerCase();
  }
  return deger.toFixed(2);
}

formatla("  MERHABA  "); // "merhaba"
formatla(3.14159);        // "3.14"

Callback ve Higher-Order Functions:

typescript
// Callback tipi tanımlama (callback type definition)
type EventHandler = (event: MouseEvent) => void;

function tiklaEkle(el: HTMLElement, handler: EventHandler): void {
  el.addEventListener("click", handler);
}

// Generic higher-order function
function filtrele<T>(dizi: T[], kosul: (eleman: T) => boolean): T[] {
  return dizi.filter(kosul);
}

const buyukSayilar = filtrele([1, 5, 10, 15], (n) => n > 8);
// buyukSayilar: number[] = [10, 15]

this Parametresi:

typescript
interface Buton {
  etiket: string;
  tiklandi(this: Buton): void;
}

const btn: Buton = {
  etiket: "Gonder",
  tiklandi() {
    // `this` burada Buton tipinde (this is of type Buton here)
    console.log(`${this.etiket} tiklandi`);
  }
};

Summary: Dönüş tiplerini açıkça yaz. Optional param ?, rest param ...args: T[]. Overload karmaşık imzalar için.


5) Generics (Genel Tipler)

Temel Generic (Basic Generic):

typescript
// T bir tip parametresi — çağıran belirler
// (T is a type parameter — the caller determines it)
function kimlik<T>(deger: T): T {
  return deger;
}

kimlik<string>("merhaba"); // açıkça belirt (explicitly specify)
kimlik(42);                 // TypeScript çıkarır: number (infers: number)

Generic Interface ve Type:

typescript
// Generic API yanıt sarmalayıcı (API response wrapper)
interface ApiYanit<T> {
  data: T;
  basarili: boolean;
  mesaj: string;
  zaman: number;
}

type KullaniciYanit = ApiYanit<Kullanici>;
type UrunListesi = ApiYanit<Urun[]>;

// Kullanım (usage)
async function veriCek<T>(url: string): Promise<ApiYanit<T>> {
  const res = await fetch(url);
  const data: T = await res.json();
  return { data, basarili: true, mesaj: "OK", zaman: Date.now() };
}

const kullanicilar = await veriCek<Kullanici[]>("/api/users");

Generic Constraints (Kısıtlamalar — Constraints):

typescript
// T, en az { length: number } özelliğine sahip olmalı
// (T must have at least { length: number } property)
function enUzun<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b;
}

enUzun("abc", "ab");         // "abc"
enUzun([1, 2, 3], [4, 5]);   // [1, 2, 3]
// enUzun(10, 20);            // HATA: number'da length yok

// keyof ile kısıtlama (constraint with keyof)
function ozellikAl<T, K extends keyof T>(obj: T, anahtar: K): T[K] {
  return obj[anahtar];
}

const kullanici = { isim: "Fahri", yas: 28 };
ozellikAl(kullanici, "isim"); // string döner (returns string)
// ozellikAl(kullanici, "boy"); // HATA: "boy" geçerli anahtar değil

Generic Sınıflar (Generic Classes):

typescript
class Koleksiyon<T> {
  private elemanlar: T[] = [];

  ekle(eleman: T): void {
    this.elemanlar.push(eleman);
  }

  al(index: number): T | undefined {
    return this.elemanlar[index];
  }

  filtrele(kosul: (eleman: T) => boolean): T[] {
    return this.elemanlar.filter(kosul);
  }

  get boyut(): number {
    return this.elemanlar.length;
  }
}

const sayilar = new Koleksiyon<number>();
sayilar.ekle(10);
sayilar.ekle(20);
sayilar.filtrele((n) => n > 15); // [20]

Birden Fazla Generic Parametre (Multiple Generic Parameters):

typescript
function eslestir<K, V>(anahtar: K, deger: V): [K, V] {
  return [anahtar, deger];
}

// Map benzeri yapılar (map-like structures)
class BiMap<K, V> {
  private ileri = new Map<K, V>();
  private geri = new Map<V, K>();

  set(anahtar: K, deger: V): void {
    this.ileri.set(anahtar, deger);
    this.geri.set(deger, anahtar);
  }

  anahtardanAl(anahtar: K): V | undefined {
    return this.ileri.get(anahtar);
  }

  degerdanAl(deger: V): K | undefined {
    return this.geri.get(deger);
  }
}

Summary: Generics = yeniden kullanılabilir, tip-güvenli kod. <T extends Kısıt> ile sınırla, keyof ile anahtar erişim sağla.


6) Utility Types (Yardımcı Tipler)

TypeScript dahili olarak gelen yardımcı tipler. Mevcut tiplerden yeni tipler türetmek için kullanılır.
(Built-in helper types to derive new types from existing ones.)

Partial<T> — Tüm alanları opsiyonel yapar (makes all fields optional):

typescript
interface Kullanici {
  id: number;
  isim: string;
  email: string;
}

// Güncelleme fonksiyonu — sadece değişen alanları gönder
// (Update function — send only changed fields)
function kullaniciGuncelle(
  id: number,
  guncellemeler: Partial<Kullanici>
): void {
  // { isim?: string; email?: string; id?: number; }
  console.log(`Kullanıcı ${id} güncelleniyor`, guncellemeler);
}

kullaniciGuncelle(1, { isim: "Yeni İsim" }); // OK

Required<T> — Tüm alanları zorunlu yapar (makes all fields required):

typescript
interface Ayarlar {
  tema?: string;
  dil?: string;
  bildirimler?: boolean;
}

// Tam konfigürasyonu zorla (enforce full configuration)
const varsayilan: Required<Ayarlar> = {
  tema: "dark",
  dil: "tr",
  bildirimler: true
};

Pick<T, K> ve Omit<T, K>:

typescript
// Sadece belirli alanları seç (pick only specific fields)
type KullaniciOnizleme = Pick<Kullanici, "isim" | "email">;
// { isim: string; email: string; }

// Belirli alanları çıkar (omit specific fields)
type KullaniciOlusturma = Omit<Kullanici, "id">;
// { isim: string; email: string; }

Record<K, V> — Anahtar-değer eşlemesi (key-value mapping):

typescript
// String anahtarlı, belirli tipte değer
// (String-keyed, specific type value)
type SayfaDurumlari = Record<string, "yukleniyor" | "hazir" | "hata">;

const sayfalar: SayfaDurumlari = {
  anasayfa: "hazir",
  hakkinda: "yukleniyor",
  iletisim: "hata"
};

// Enum anahtarlı record
type RolYetkileri = Record<Rol, string[]>;

Readonly<T>:

typescript
const kullanici: Readonly<Kullanici> = {
  id: 1,
  isim: "Fahri",
  email: "test@test.com"
};
// kullanici.isim = "Baska"; // HATA: readonly

ReturnType<T> ve Parameters<T>:

typescript
function kullaniciOlustur(isim: string, yas: number) {
  return { id: Math.random(), isim, yas, olusturma: new Date() };
}

// Fonksiyonun dönüş tipini al (get function's return type)
type YeniKullanici = ReturnType<typeof kullaniciOlustur>;
// { id: number; isim: string; yas: number; olusturma: Date; }

// Fonksiyonun parametre tiplerini al (get function's parameter types)
type OlusturmaParams = Parameters<typeof kullaniciOlustur>;
// [isim: string, yas: number]

Exclude<T, U> ve Extract<T, U>:

typescript
type Durum = "aktif" | "pasif" | "beklemede" | "silindi";

// Belirli tipleri çıkar (exclude specific types)
type AktifDurumlar = Exclude<Durum, "silindi" | "pasif">;
// "aktif" | "beklemede"

// Belirli tipleri seç (extract specific types)
type SonDurumlar = Extract<Durum, "aktif" | "pasif">;
// "aktif" | "pasif"

NonNullable<T>:

typescript
type BelkiString = string | null | undefined;
type KesinString = NonNullable<BelkiString>;
// string

Utility Types Tablosu (Summary Table):

Utility TypeAçıklama (Description)Örnek (Example)
Partial<T>Tüm alanlar opsiyonel (all fields optional)Güncelleme DTO
Required<T>Tüm alanlar zorunlu (all fields required)Varsayılan config
Pick<T, K>Belirli alanları seç (pick specific fields)Önizleme tipleri
Omit<T, K>Belirli alanları çıkar (omit specific fields)Oluşturma DTO
Record<K, V>Anahtar-değer haritası (key-value map)Lookup tabloları
Readonly<T>Değiştirilemez (immutable)State, config
ReturnType<F>Fonksiyon dönüş tipi (function return type)Tip çıkarımı
Parameters<F>Fonksiyon param tipleri (function param types)Wrapper fonksiyonlar
Exclude<T, U>Union'dan çıkar (exclude from union)Filtreleme
Extract<T, U>Union'dan seç (extract from union)Filtreleme
NonNullable<T>null/undefined çıkar (remove null/undefined)Güvenli erişim

Summary: Utility types mevcut tiplerden yeni tipler türetir. En çok Partial, Pick, Omit, Record kullanılır.


7) Union & Intersection Types (Birleşim ve Kesişim Tipleri)

Union Types (Birleşim Tipleri) — |

typescript
// Değer birden fazla tipten biri olabilir (value can be one of multiple types)
type Sonuc = string | number;
type Durum = "basarili" | "basarisiz" | "beklemede";

function idYazdir(id: string | number): void {
  // Type narrowing — tip daraltma
  if (typeof id === "string") {
    console.log(id.toUpperCase()); // string metodları kullanılabilir
  } else {
    console.log(id.toFixed(2));    // number metodları kullanılabilir
  }
}

Intersection Types (Kesişim Tipleri) — &

typescript
type Zamandamgali = {
  olusturma: Date;
  guncelleme: Date;
};

type YumusaSilme = {
  silindiMi: boolean;
  silinmeZamani?: Date;
};

// Intersection — tüm alanları içerir (includes all fields)
type VeritabaniKaydi = Kullanici & Zamandamgali & YumusaSilme;

// Kullanım (usage)
const kayit: VeritabaniKaydi = {
  id: 1,
  isim: "Fahri",
  email: "fahri@test.com",
  olusturma: new Date(),
  guncelleme: new Date(),
  silindiMi: false
};

Discriminated Unions (Ayırt Edici Birleşimler — Tagged Unions):

typescript
// Ortak bir alan ile tipleri ayırt et (distinguish types with a common field)
type BasariliSonuc = {
  durum: "basarili";
  data: unknown;
};

type HataSonuc = {
  durum: "hata";
  hataMesaji: string;
  hataKodu: number;
};

type YuklemeSonuc = {
  durum: "yukleniyor";
};

type IslemSonuc = BasariliSonuc | HataSonuc | YuklemeSonuc;

function sonucIsle(sonuc: IslemSonuc): string {
  switch (sonuc.durum) {
    case "basarili":
      return `Veri: ${JSON.stringify(sonuc.data)}`;
    case "hata":
      return `Hata ${sonuc.hataKodu}: ${sonuc.hataMesaji}`;
    case "yukleniyor":
      return "Yükleniyor...";
  }
}

Type Guards (Tip Korumaları):

typescript
// typeof guard
function isleYap(deger: string | number): string {
  if (typeof deger === "string") return deger.toUpperCase();
  return String(deger);
}

// instanceof guard
class Api404Hatasi extends Error {
  statusCode = 404;
}

function hataIsle(hata: Error) {
  if (hata instanceof Api404Hatasi) {
    console.log(`Sayfa bulunamadı: ${hata.statusCode}`);
  }
}

// Custom type guard — in operatörü (in operator)
interface Kus { ucar(): void; }
interface Balik { yuzer(): void; }

function kustur(hayvan: Kus | Balik): hayvan is Kus {
  return "ucar" in hayvan;
}

// Custom type guard — kullanıcı tanımlı (user-defined)
function diziMi<T>(deger: T | T[]): deger is T[] {
  return Array.isArray(deger);
}

Exhaustiveness Checking (Tükenmişlik Kontrolü — Exhaustive Check):

typescript
// never ile tüm durumlar karşılandı mı kontrol et
// (check if all cases are handled using never)
type Sekil =
  | { tur: "daire"; yaricap: number }
  | { tur: "kare"; kenar: number }
  | { tur: "ucgen"; taban: number; yukseklik: number };

function alanHesapla(sekil: Sekil): number {
  switch (sekil.tur) {
    case "daire":
      return Math.PI * sekil.yaricap ** 2;
    case "kare":
      return sekil.kenar ** 2;
    case "ucgen":
      return (sekil.taban * sekil.yukseklik) / 2;
    default:
      // Yeni bir tür eklersen burada derleme hatası alırsın
      // (if you add a new type, you'll get a compile error here)
      const _exhaustive: never = sekil;
      return _exhaustive;
  }
}

Summary: Union | = veya, Intersection & = ve. Discriminated union + switch = güvenli tip daraltma.


8) Type Assertions & Casting (Tip Bildirimleri ve Dönüştürme)

as Keyword (Tip Bildirimi — Type Assertion):

typescript
// DOM element tipleri için yaygın kullanım (common for DOM element types)
const input = document.getElementById("email") as HTMLInputElement;
input.value = "test@test.com";

// API yanıtları için (for API responses)
const data = JSON.parse(jsonString) as Kullanici;

// Dikkat: as tip kontrolü yapmaz, sadece derleyiciye söyler
// (Caution: as doesn't check types, only tells the compiler)
// Yanlış kullanım runtime hatası verebilir
const yanlis = "merhaba" as unknown as number; // tehlikeli!

satisfies Operatörü (TS 4.9+):

typescript
// satisfies tipi kontrol eder AMA orijinal tipi korur
// (satisfies checks the type BUT preserves the original type)
type Renkler = Record<string, string | string[]>;

const temalar = {
  birincil: "#0066cc",
  ikincil: "#666",
  uyari: ["#ff0", "#f00"]
} satisfies Renkler;

// Avantaj: TypeScript her alanın tipini biliyor
// (Advantage: TypeScript knows the type of each field)
temalar.birincil.toUpperCase();     // OK — string olduğunu biliyor
temalar.uyari.map(r => r.trim());   // OK — string[] olduğunu biliyor

// `as Renkler` ile bu çalışmazdı:
// const temalar2: Renkler = { ... };
// temalar2.birincil.toUpperCase(); // HATA — string | string[]

const Assertions:

typescript
// as const — değerleri literal tip yapar, readonly yapar
// (makes values literal types and readonly)
const config = {
  api: "https://api.example.com",
  port: 3000,
  modlar: ["gelistirme", "uretim"]
} as const;

// Tip: { readonly api: "https://api.example.com"; readonly port: 3000; readonly modlar: readonly ["gelistirme", "uretim"]; }
// config.port = 4000; // HATA: readonly
// config.modlar.push("test"); // HATA: readonly

// Enum yerine kullanılabilir (can be used instead of enum)
const YONLER = ["kuzey", "guney", "dogu", "bati"] as const;
type Yon = typeof YONLER[number]; // "kuzey" | "guney" | "dogu" | "bati"

Non-null Assertion (!):

typescript
// Derleyiciye "bu null/undefined değildir" demek
// (Telling the compiler "this is not null/undefined")
function isleYap(deger: string | null): void {
  // Dikkatli kullan — runtime null olursa patlar
  // (Use carefully — crashes at runtime if null)
  console.log(deger!.length);
}

// Daha güvenli alternatif: optional chaining + nullish coalescing
// (Safer alternative)
function guvenliIsle(deger: string | null): void {
  console.log(deger?.length ?? 0);
}

Summary: as dikkatli kullan. satisfies tip güvenliğini korur. as const literal tipler için. ! yerine ?. ve ?? tercih et.


9) Modules & Namespaces (Modüller ve İsim Alanları)

ES Modules — import/export:

typescript
// --- utils.ts ---
export function formatTarih(tarih: Date): string {
  return tarih.toLocaleDateString("tr-TR");
}

export const PI = 3.14159;

// Default export
export default class Logger {
  log(mesaj: string): void {
    console.log(`[LOG] ${mesaj}`);
  }
}

// --- app.ts ---
import Logger, { formatTarih, PI } from "./utils";

const logger = new Logger();
logger.log(formatTarih(new Date()));

Type-only Imports (Sadece tip import — type-only import):

typescript
// Tip importları derleme çıktısında yer almaz — bundle boyutunu etkilemez
// (Type imports are removed from compiled output — doesn't affect bundle size)
import type { Kullanici, Urun } from "./types";

// Inline type import
import { type Kullanici, formatTarih } from "./utils";

Declaration Files (.d.ts):

typescript
// --- global.d.ts ---
// Global tip tanımlamaları, import/export olmadan
// (Global type declarations, without import/export)
declare global {
  interface Window {
    analitiik: {
      izle(olay: string, veri?: Record<string, unknown>): void;
    };
  }
}

// --- custom-module.d.ts ---
// Tipsiz bir modüle tip eklemek (adding types to an untyped module)
declare module "eski-kutuphane" {
  export function eskiFonksiyon(param: string): number;
}

// CSS modülleri için (for CSS modules)
declare module "*.css" {
  const classes: Record<string, string>;
  export default classes;
}

// SVG dosyaları için (for SVG files)
declare module "*.svg" {
  const content: string;
  export default content;
}

@types Paketleri (Packages):

bash
# Topluluk tip tanımları (community type definitions)
npm install --save-dev @types/node
npm install --save-dev @types/react
npm install --save-dev @types/express

# Paketin kendi tip tanımları varsa @types gerekmez
# (if the package has its own type definitions, @types is not needed)
# package.json içinde "types" alanı kontrol et

Barrel Exports (Toplu Export):

typescript
// --- models/index.ts ---
export type { Kullanici } from "./kullanici";
export type { Urun } from "./urun";
export type { Siparis } from "./siparis";
export { KullaniciService } from "./kullanici.service";
export { UrunService } from "./urun.service";

// --- app.ts ---
import { Kullanici, UrunService } from "./models";

Summary: import type kullan, bundle boyutu küçülür. .d.ts dosyaları tipsiz kütüphaneler için. @types/* topluluk tipleri.


10) React + TypeScript

Component Props:

tsx
// Props interface tanımla (define Props interface)
interface ButtonProps {
  etiket: string;
  onClick: () => void;
  variant?: "primary" | "secondary" | "danger";
  devre_disi?: boolean;
  children?: React.ReactNode;
}

// Fonksiyonel component
const Button: React.FC<ButtonProps> = ({
  etiket,
  onClick,
  variant = "primary",
  devre_disi = false,
  children
}) => (
  <button
    className={`btn btn-${variant}`}
    onClick={onClick}
    disabled={devre_disi}
  >
    {children ?? etiket}
  </button>
);

// React.FC olmadan (tercih edilen modern yaklaşım)
// (without React.FC — preferred modern approach)
function Card({ baslik, children }: { baslik: string; children: React.ReactNode }) {
  return (
    <div className="card">
      <h2>{baslik}</h2>
      {children}
    </div>
  );
}

useState:

tsx
import { useState } from "react";

function SayacComponent() {
  // Tip çıkarılır (type is inferred)
  const [sayac, setSayac] = useState(0);

  // Açıkça belirt — özellikle null/union olabilirse
  // (Explicitly specify — especially if it can be null/union)
  const [kullanici, setKullanici] = useState<Kullanici | null>(null);

  // Dizi state (array state)
  const [elemanlar, setElemanlar] = useState<Urun[]>([]);

  const urunEkle = (urun: Urun) => {
    setElemanlar((onceki) => [...onceki, urun]);
  };

  return <div>{sayac}</div>;
}

useRef:

tsx
import { useRef, useEffect } from "react";

function GirisFormu() {
  // DOM ref — başlangıçta null (initially null)
  const inputRef = useRef<HTMLInputElement>(null);

  // Değişken ref (mutable) — render tetiklemez
  // (Mutable ref — doesn't trigger render)
  const zamanlayiciRef = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    inputRef.current?.focus();

    zamanlayiciRef.current = setInterval(() => {
      console.log("tik");
    }, 1000);

    return () => {
      if (zamanlayiciRef.current) clearInterval(zamanlayiciRef.current);
    };
  }, []);

  return <input ref={inputRef} type="text" placeholder="Email" />;
}

Event Handlers:

tsx
function FormComponent() {
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    // form işleme (form processing)
  };

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    console.log(e.target.value);
  };

  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    console.log("tıklandı", e.clientX, e.clientY);
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Enter") console.log("Enter basıldı");
  };

  return (
    <form onSubmit={handleSubmit}>
      <input onChange={handleChange} onKeyDown={handleKeyDown} />
      <button onClick={handleClick}>Gönder</button>
    </form>
  );
}

Context API:

tsx
import { createContext, useContext, useState, type ReactNode } from "react";

interface TemaContext {
  tema: "acik" | "koyu";
  degistir: () => void;
}

const TemaCtx = createContext<TemaContext | null>(null);

// Custom hook — güvenli erişim (safe access)
function useTema(): TemaContext {
  const ctx = useContext(TemaCtx);
  if (!ctx) throw new Error("useTema, TemaProvider içinde kullanılmalı");
  return ctx;
}

function TemaProvider({ children }: { children: ReactNode }) {
  const [tema, setTema] = useState<"acik" | "koyu">("acik");

  const degistir = () => setTema((t) => (t === "acik" ? "koyu" : "acik"));

  return (
    <TemaCtx.Provider value={{ tema, degistir }}>
      {children}
    </TemaCtx.Provider>
  );
}

Custom Hooks Typing (Özel Hook Tiplendirme):

tsx
// Generic custom hook
function useLocalStorage<T>(
  anahtar: string,
  varsayilan: T
): [T, (deger: T | ((onceki: T) => T)) => void] {
  const [deger, setDeger] = useState<T>(() => {
    try {
      const kayitli = localStorage.getItem(anahtar);
      return kayitli ? (JSON.parse(kayitli) as T) : varsayilan;
    } catch {
      return varsayilan;
    }
  });

  const kaydet = (yeniDeger: T | ((onceki: T) => T)) => {
    setDeger((onceki) => {
      const sonuc = yeniDeger instanceof Function ? yeniDeger(onceki) : yeniDeger;
      localStorage.setItem(anahtar, JSON.stringify(sonuc));
      return sonuc;
    });
  };

  return [deger, kaydet];
}

// Fetch hook
interface FetchDurumu<T> {
  data: T | null;
  yukleniyor: boolean;
  hata: string | null;
}

function useFetch<T>(url: string): FetchDurumu<T> {
  const [durum, setDurum] = useState<FetchDurumu<T>>({
    data: null,
    yukleniyor: true,
    hata: null
  });

  useEffect(() => {
    const controller = new AbortController();

    fetch(url, { signal: controller.signal })
      .then((res) => res.json() as Promise<T>)
      .then((data) => setDurum({ data, yukleniyor: false, hata: null }))
      .catch((err: Error) => {
        if (err.name !== "AbortError") {
          setDurum({ data: null, yukleniyor: false, hata: err.message });
        }
      });

    return () => controller.abort();
  }, [url]);

  return durum;
}

Summary: Props için interface tanımla. useState<T>, useRef<T> ile tip belirt. Context için custom hook + null kontrol. Event tiplerine dikkat.


11) Node.js + TypeScript

Kurulum (Setup):

bash
npm init -y
npm install --save-dev typescript @types/node ts-node nodemon

# Express projesi için (for Express project)
npm install express
npm install --save-dev @types/express

Node.js için tsconfig.json:

json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Express Typed Routes:

typescript
import express, {
  type Request,
  type Response,
  type NextFunction,
  type Router
} from "express";

// Request body, params, query tipleri (types)
interface KullaniciBody {
  isim: string;
  email: string;
  sifre: string;
}

interface IdParams {
  id: string;
}

interface SayfalamaQuery {
  sayfa?: string;
  limit?: string;
  siralama?: "asc" | "desc";
}

const router: Router = express.Router();

// GET /api/kullanicilar?sayfa=1&limit=10
router.get(
  "/kullanicilar",
  async (
    req: Request<{}, {}, {}, SayfalamaQuery>,
    res: Response
  ) => {
    const sayfa = parseInt(req.query.sayfa ?? "1");
    const limit = parseInt(req.query.limit ?? "10");

    // veritabanı sorgusu... (database query...)
    res.json({ sayfa, limit, data: [] });
  }
);

// POST /api/kullanicilar
router.post(
  "/kullanicilar",
  async (
    req: Request<{}, {}, KullaniciBody>,
    res: Response
  ) => {
    const { isim, email, sifre } = req.body;
    // kullanıcı oluştur... (create user...)
    res.status(201).json({ isim, email });
  }
);

// GET /api/kullanicilar/:id
router.get(
  "/kullanicilar/:id",
  async (
    req: Request<IdParams>,
    res: Response
  ) => {
    const { id } = req.params;
    // kullanıcı bul... (find user...)
    res.json({ id });
  }
);

Typed Middleware:

typescript
// Hata yakalama middleware (error catching middleware)
interface ApiHata extends Error {
  statusCode: number;
  detaylar?: Record<string, unknown>;
}

function hataYakalayici(
  err: ApiHata,
  _req: Request,
  res: Response,
  _next: NextFunction
): void {
  const statusCode = err.statusCode ?? 500;
  res.status(statusCode).json({
    basarili: false,
    mesaj: err.message,
    detaylar: err.detaylar
  });
}

// Auth middleware — Request'e kullanıcı ekle (add user to Request)
interface KimlikliRequest extends Request {
  kullanici?: { id: string; rol: string };
}

function kimlikDogrula(
  req: KimlikliRequest,
  _res: Response,
  next: NextFunction
): void {
  const token = req.headers.authorization?.split(" ")[1];
  if (!token) {
    const hata = new Error("Yetkisiz") as ApiHata;
    hata.statusCode = 401;
    return next(hata);
  }
  // token doğrula... (verify token...)
  req.kullanici = { id: "123", rol: "admin" };
  next();
}

// Validasyon middleware fabrikası (validation middleware factory)
function dogrula<T>(sema: { parse: (data: unknown) => T }) {
  return (req: Request, _res: Response, next: NextFunction) => {
    try {
      req.body = sema.parse(req.body);
      next();
    } catch (err) {
      next(err);
    }
  };
}

Environment Variables (Ortam Değişkenleri):

typescript
// env.ts — tip-güvenli ortam değişkenleri (type-safe environment variables)
function envAl(anahtar: string, varsayilan?: string): string {
  const deger = process.env[anahtar];
  if (deger === undefined) {
    if (varsayilan !== undefined) return varsayilan;
    throw new Error(`Ortam değişkeni eksik: ${anahtar}`);
  }
  return deger;
}

const config = {
  port: parseInt(envAl("PORT", "3000")),
  dbUrl: envAl("DATABASE_URL"),
  nodeEnv: envAl("NODE_ENV", "development") as "development" | "production" | "test",
  jwtSecret: envAl("JWT_SECRET"),
} as const;

export default config;

Summary: Express Request<Params, ResBody, ReqBody, Query> generic sıralaması. Middleware tiplendirmesi. Env değişkenleri için wrapper fonksiyon.


12) Conditional Types ve Infer (Koşullu Tipler ve Çıkarım)

Temel Conditional Type (Basic Conditional Type):

Conditional type, tip seviyesinde koşullu mantık kurmaya yarar. T extends U ? X : Y şeklinde yazılır. (Conditional types enable conditional logic at the type level. Written as T extends U ? X : Y.)

typescript
// T, string'den türetiliyorsa "evet", değilse "hayır"
// (If T extends string, "evet"; otherwise "hayır")
type StringMi<T> = T extends string ? "evet" : "hayir";

type A = StringMi<"merhaba">; // "evet"
type B = StringMi<42>;         // "hayir"

// Pratik örnek: null olabilecek tipleri filtreleme
// (Practical example: filtering nullable types)
type NonNullable<T> = T extends null | undefined ? never : T;
type C = NonNullable<string | null | undefined>; // string

Distributive Conditional Types (Dağıtımlı Koşullu Tipler):

Union tipler üzerinde conditional type uygulandığında, her bir üye ayrı ayrı değerlendirilir. (When a conditional type is applied to union types, each member is evaluated separately.)

typescript
type SadeceSayilar<T> = T extends number ? T : never;

type D = SadeceSayilar<string | number | boolean | 42>;
// number | 42 — string ve boolean elendi

// Bu dağılım davranışını engellemek için tuple kullan
// (Use tuple to prevent this distributive behavior)
type DiziMi<T> = [T] extends [unknown[]] ? "evet" : "hayir";
type E = DiziMi<string | number[]>; // "hayir" — dağılım olmadı

infer Anahtar Kelimesi (infer Keyword):

infer, bir tip içinden alt tip çıkarmanızı sağlar. (infer allows you to extract a sub-type from within a type.)

typescript
// Fonksiyon dönüş tipini çıkarma (ReturnType'ın mantığı)
// (Extracting function return type — ReturnType's logic)
type DonusTipi<T> = T extends (...args: any[]) => infer R ? R : never;

type F = DonusTipi<() => string>;           // string
type G = DonusTipi<(x: number) => boolean>; // boolean

// Promise içindeki tipi çıkarma (extracting the type inside a Promise)
type PromiseIci<T> = T extends Promise<infer U> ? U : T;

type H = PromiseIci<Promise<string>>;    // string
type I = PromiseIci<Promise<number[]>>;  // number[]
type J = PromiseIci<string>;             // string — Promise değilse aynen döner

// Dizi eleman tipini çıkarma (extracting array element type)
type DiziEleman<T> = T extends (infer U)[] ? U : never;

type K = DiziEleman<string[]>;    // string
type L = DiziEleman<[1, "a", true]>; // 1 | "a" | true

Gerçek Dünya Örnekleri (Real-World Examples):

typescript
// API yanıt tipinden data alanını çıkar
// (Extract the data field from API response type)
type ApiData<T> = T extends { data: infer D } ? D : never;

interface KullaniciYaniti {
  data: { id: number; isim: string };
  basarili: boolean;
}

type KullaniciData = ApiData<KullaniciYaniti>;
// { id: number; isim: string }

// Event handler tipinden event tipini çıkar
// (Extract event type from event handler type)
type EventTipi<T> = T extends (event: infer E) => void ? E : never;

type ClickEvent = EventTipi<(event: MouseEvent) => void>; // MouseEvent

// Recursive conditional type — derin Promise açma (deep Promise unwrapping)
type DerinAwait<T> = T extends Promise<infer U> ? DerinAwait<U> : T;

type M = DerinAwait<Promise<Promise<Promise<string>>>>; // string

Summary: Conditional types tip seviyesinde if-else sağlar. infer ile alt tip çıkarımı yapılır. Distributive davranış union'larda otomatiktir.


13) Mapped Types ve Template Literal Types (Eşlenmiş Tipler ve Şablon Metin Tipleri)

Temel Mapped Types (Basic Mapped Types):

Mapped type, mevcut bir tipin anahtarları üzerinde döngü kurarak yeni bir tip oluşturur. (Mapped types create a new type by iterating over the keys of an existing type.)

typescript
// Tüm alanları opsiyonel yapma (Partial'ın mantığı)
// (Making all fields optional — Partial's logic)
type Opsiyonel<T> = {
  [K in keyof T]?: T[K];
};

// Tüm alanları readonly yapma (making all fields readonly)
type SaltOkunur<T> = {
  readonly [K in keyof T]: T[K];
};

// Tüm alanları nullable yapma (making all fields nullable)
type Nullable<T> = {
  [K in keyof T]: T[K] | null;
};

interface Kullanici {
  id: number;
  isim: string;
  email: string;
}

type NullableKullanici = Nullable<Kullanici>;
// { id: number | null; isim: string | null; email: string | null }

Anahtar Yeniden Eşleme (Key Remapping — TS 4.1+):

typescript
// Anahtarlara önek ekleme (adding prefix to keys)
type Getter<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type KullaniciGetters = Getter<Kullanici>;
// { getId: () => number; getIsim: () => string; getEmail: () => string }

// Belirli tipteki alanları filtreleme (filtering fields by type)
type SadeceStringler<T> = {
  [K in keyof T as T[K] extends string ? K : never]: T[K];
};

type StringAlanlar = SadeceStringler<Kullanici>;
// { isim: string; email: string } — id (number) elendi

Custom Mapped Type Örnekleri (Custom Mapped Type Examples):

typescript
// Form state: her alan için değer + hata + dokunuldu bilgisi
// (Form state: value + error + touched info for each field)
type FormState<T> = {
  [K in keyof T]: {
    deger: T[K];
    hata: string | null;
    dokunuldu: boolean;
  };
};

type KullaniciForm = FormState<Omit<Kullanici, "id">>;
// {
//   isim: { deger: string; hata: string | null; dokunuldu: boolean };
//   email: { deger: string; hata: string | null; dokunuldu: boolean };
// }

// Event handler haritası (event handler map)
type EventHandlers<T> = {
  [K in keyof T as `on${Capitalize<string & K>}Change`]: (yeniDeger: T[K]) => void;
};

type KullaniciHandlers = EventHandlers<Kullanici>;
// { onIdChange: (yeniDeger: number) => void; onIsimChange: ... }

Template Literal Types (Şablon Metin Tipleri):

typescript
// String birleştirme tipleri (string concatenation types)
type Renk = "kirmizi" | "mavi" | "yesil";
type Boyut = "kucuk" | "orta" | "buyuk";

type RenkBoyut = `${Renk}-${Boyut}`;
// "kirmizi-kucuk" | "kirmizi-orta" | "kirmizi-buyuk" | "mavi-kucuk" | ...

// CSS birim tipleri (CSS unit types)
type CSSBirim = "px" | "rem" | "em" | "%";
type CSSDeger = `${number}${CSSBirim}`;

const genislik: CSSDeger = "100px";    // OK
const yukseklik: CSSDeger = "2.5rem";  // OK
// const hatali: CSSDeger = "abc";     // HATA

// API endpoint tipleri (API endpoint types)
type HTTPMetod = "GET" | "POST" | "PUT" | "DELETE";
type Endpoint = `/api/${"users" | "products" | "orders"}`;

type APIRoute = `${HTTPMetod} ${Endpoint}`;
// "GET /api/users" | "GET /api/products" | "POST /api/users" | ...

// Intrinsic string manipulation types
type A = Uppercase<"merhaba">;    // "MERHABA"
type B = Lowercase<"MERHABA">;    // "merhaba"
type C = Capitalize<"merhaba">;   // "Merhaba"
type D = Uncapitalize<"Merhaba">; // "merhaba"

Summary: Mapped types mevcut tip anahtarlarını dönüştürür. Template literal types string tipler üzerinde birleştirme ve manipülasyon sağlar.


14) Type Guards, Assertion Functions ve Tip Daraltma (Type Narrowing)

is Anahtar Kelimesi ile Type Guard (Type Guard with is Keyword):

typescript
interface Yonetici {
  tur: "yonetici";
  isim: string;
  departman: string;
}

interface Calisan {
  tur: "calisan";
  isim: string;
  pozisyon: string;
}

type Personel = Yonetici | Calisan;

// Type predicate — dönüş tipi `parametre is Tip`
// (return type is `parameter is Type`)
function yoneticiMi(kisi: Personel): kisi is Yonetici {
  return kisi.tur === "yonetici";
}

function personelBilgi(kisi: Personel): string {
  if (yoneticiMi(kisi)) {
    // TypeScript burada kişinin Yönetici olduğunu biliyor
    // (TypeScript knows kisi is Yonetici here)
    return `${kisi.isim} - ${kisi.departman}`;
  }
  // Burada otomatik olarak Çalışan
  // (Automatically Calisan here)
  return `${kisi.isim} - ${kisi.pozisyon}`;
}

in Operatörü ile Tip Daraltma (Type Narrowing with in Operator):

typescript
interface Araba {
  sur(): void;
  tekerlekSayisi: 4;
}

interface Gemi {
  yelkenAc(): void;
  derinlik: number;
}

function aracKullan(arac: Araba | Gemi): void {
  if ("sur" in arac) {
    arac.sur(); // TypeScript: Araba
  } else {
    arac.yelkenAc(); // TypeScript: Gemi
  }
}

instanceof ile Sınıf Kontrolü (Class Check with instanceof):

typescript
class DogrulamaHatasi extends Error {
  alanlar: Record<string, string>;

  constructor(mesaj: string, alanlar: Record<string, string>) {
    super(mesaj);
    this.alanlar = alanlar;
  }
}

class YetkilendirmeHatasi extends Error {
  constructor(mesaj: string) {
    super(mesaj);
  }
}

function hataYonet(hata: unknown): string {
  if (hata instanceof DogrulamaHatasi) {
    return `Form hataları: ${JSON.stringify(hata.alanlar)}`;
  }
  if (hata instanceof YetkilendirmeHatasi) {
    return `Yetkisiz: ${hata.message}`;
  }
  if (hata instanceof Error) {
    return hata.message;
  }
  return "Bilinmeyen hata";
}

Assertion Functions (asserts):

Assertion fonksiyonları, çağrı noktasından sonraki kodda tipi daraltır. Koşul sağlanmazsa hata fırlatır. (Assertion functions narrow the type in code after the call point. Throws an error if the condition is not met.)

typescript
// asserts — fonksiyon başarılı dönerse tip daraltılır
// (if the function returns successfully, the type is narrowed)
function stringOlmalidir(deger: unknown): asserts deger is string {
  if (typeof deger !== "string") {
    throw new Error(`String beklendi, ${typeof deger} alındı`);
  }
}

function nullDegilOlmalidir<T>(
  deger: T | null | undefined
): asserts deger is T {
  if (deger === null || deger === undefined) {
    throw new Error("Değer null veya undefined olmamalı");
  }
}

// Kullanım (usage)
function kullaniciIsle(veri: unknown): void {
  stringOlmalidir(veri);
  // Bu noktadan sonra veri string tipinde
  // (From this point on, veri is of type string)
  console.log(veri.toUpperCase());
}

function kayitIsle(kullanici: Kullanici | null): void {
  nullDegilOlmalidir(kullanici);
  // Bu noktadan sonra kullanıcı kesinlikle Kullanıcı tipinde
  // (From this point on, kullanici is definitely of type Kullanici)
  console.log(kullanici.isim);
}

// assert koşulu ile (with assert condition) (TS 4.8+)
function pozitifSayiOlmalidir(
  deger: number
): asserts deger is number {
  if (deger <= 0) {
    throw new RangeError(`Pozitif sayı beklendi, ${deger} alındı`);
  }
}

Tip Daraltma Yöntemleri Özet Tablosu (Type Narrowing Methods Summary):

Yöntem (Method)Sözdizimi (Syntax)Ne Zaman Kullanılır (When to Use)
typeoftypeof x === "string"Primitif tipler (string, number, boolean)
instanceofx instanceof SinifSınıf örnekleri (class instances)
in"alan" in xObje özellik kontrolü (object property check)
isfonk(x): x is TipÖzel tip guard fonksiyonu (custom type guard)
assertsfonk(x): asserts x is TipHata fırlatan doğrulama (throwing validation)
Discriminated unionx.tur === "abc"Etiketli union tipleri (tagged union types)
Array.isArrayArray.isArray(x)Dizi kontrolü (array check)

Summary: is ile type guard fonksiyonları, asserts ile doğrulama fonksiyonları tanımlayabilirsin. in ve instanceof dahili tip daraltma sağlar.


15) Declaration Files (.d.ts) Oluşturma (Creating Declaration Files)

Neden .d.ts Dosyası Gerekir? (Why Are .d.ts Files Needed?)

  • Tipsiz JavaScript kütüphanelerine tip eklemek için (to add types to untyped JS libraries)
  • Global değişken ve fonksiyonları tanımlamak için (to declare global variables and functions)
  • Module augmentation (mevcut modülleri genişletmek) için (to extend existing modules)
  • NPM paketinde tip dağıtmak için (to distribute types in NPM packages)

Temel .d.ts Yapısı (Basic .d.ts Structure):

typescript
// --- analytics.d.ts ---
// Dışarıdan yüklenen bir analytics kütüphanesi için tip tanımlaması
// (Type declaration for an externally loaded analytics library)

declare namespace Analytics {
  interface Event {
    kategori: string;
    aksiyon: string;
    etiket?: string;
    deger?: number;
  }

  function izle(event: Event): void;
  function sayfaGoruntulemesi(yol: string): void;

  interface Config {
    trackingId: string;
    debug?: boolean;
    anonymize?: boolean;
  }

  function baslat(config: Config): void;
}

// Global değişken olarak erişilebilir (accessible as a global variable)
declare const analytics: typeof Analytics;

Module Declaration:

typescript
// --- untyped-lib.d.ts ---
// Tipleri olmayan bir npm paketi için (for an npm package without types)
declare module "untyped-lib" {
  export interface Options {
    format?: "json" | "xml" | "csv";
    encoding?: string;
  }

  export function parse(input: string, options?: Options): unknown;
  export function stringify(data: unknown): string;

  export default class Client {
    constructor(baseUrl: string);
    get<T>(path: string): Promise<T>;
    post<T>(path: string, body: unknown): Promise<T>;
  }
}

Module Augmentation — Mevcut Tipleri Genişletme (Extending Existing Types):

typescript
// --- express-augment.d.ts ---
// Express Request'e özel alan eklemek (adding custom fields to Express Request)
import "express";

declare module "express" {
  interface Request {
    kullanici?: {
      id: string;
      email: string;
      roller: string[];
    };
    istekId?: string;
  }
}

// --- env.d.ts ---
// process.env için tip tanımlaması (type declaration for process.env)
declare namespace NodeJS {
  interface ProcessEnv {
    NODE_ENV: "development" | "production" | "test";
    PORT: string;
    DATABASE_URL: string;
    JWT_SECRET: string;
    REDIS_URL?: string;
  }
}

Dosya Uzantıları için Declaration (Declaration for File Extensions):

typescript
// --- assets.d.ts ---
// Statik dosya importları için (for static file imports)
declare module "*.png" {
  const src: string;
  export default src;
}

declare module "*.jpg" {
  const src: string;
  export default src;
}

declare module "*.module.css" {
  const classes: Record<string, string>;
  export default classes;
}

declare module "*.module.scss" {
  const classes: Record<string, string>;
  export default classes;
}

declare module "*.json" {
  const value: Record<string, unknown>;
  export default value;
}

NPM Paketi için Tip Dağıtımı (Type Distribution for NPM Package):

json
// package.json
{
  "name": "my-library",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"]
}
typescript
// tsconfig.json içinde declaration açık olmalı
// (declaration must be enabled in tsconfig.json)
// "declaration": true,
// "declarationMap": true  — kaynak koduna atlama için (for jumping to source code)

Summary: .d.ts dosyaları runtime'da çalıştırılmaz, sadece tip bilgisi sağlar. Module augmentation ile mevcut tipleri genişletebilirsin.


16) Zod ile Runtime Validation (Runtime Validation with Zod)

TypeScript tipleri sadece derleme zamanında çalışır, runtime'da kaybolur. Zod, runtime'da da tip güvenliğini sağlar. (TypeScript types only work at compile time and disappear at runtime. Zod provides type safety at runtime too.)

Kurulum ve Temel Kullanım (Installation and Basic Usage):

bash
npm install zod
typescript
import { z } from "zod";

// Schema tanımla — hem validator hem de tip çıkarır
// (Define schema — both validator and type inference)
const KullaniciSemasi = z.object({
  isim: z.string().min(2, "İsim en az 2 karakter olmalı"),
  email: z.string().email("Geçerli email giriniz"),
  yas: z.number().int().min(18, "En az 18 yaş").max(120),
  rol: z.enum(["admin", "kullanici", "moderator"]),
  adres: z.object({
    sehir: z.string(),
    postaKodu: z.string().regex(/^\d{5}$/, "5 haneli posta kodu"),
  }).optional(),
});

// Schema'dan TypeScript tipini çıkar (infer TypeScript type from schema)
type Kullanici = z.infer<typeof KullaniciSemasi>;
// { isim: string; email: string; yas: number; rol: "admin" | "kullanici" | "moderator"; adres?: {...} }

parse vs safeParse:

typescript
// parse — geçersiz veride Error fırlatır (throws Error on invalid data)
try {
  const kullanici = KullaniciSemasi.parse(disardanGelenVeri);
  // kullanıcı burada tip-güvenli Kullanıcı
  // (kullanici is type-safe Kullanici here)
  console.log(kullanici.isim);
} catch (hata) {
  if (hata instanceof z.ZodError) {
    console.log(hata.errors);
    // [{ path: ["email"], message: "Geçerli email giriniz", code: "invalid_string" }]
  }
}

// safeParse — Error fırlatmaz, sonuç objesi döner
// (doesn't throw Error, returns result object)
const sonuc = KullaniciSemasi.safeParse(disardanGelenVeri);

if (sonuc.success) {
  // sonuc.data tip-güvenli Kullanıcı (type-safe Kullanici)
  console.log(sonuc.data.isim);
} else {
  // sonuc.error ZodError
  const hataDetaylari = sonuc.error.flatten();
  console.log(hataDetaylari.fieldErrors);
  // { email: ["Geçerli email giriniz"], yas: ["En az 18 yaş"] }
}

Sık Kullanılan Zod Yöntemleri (Commonly Used Zod Methods):

typescript
// String validasyonları (string validations)
const EmailSemasi = z.string().email().toLowerCase().trim();
const SifreSemasi = z.string().min(8).max(64)
  .regex(/[A-Z]/, "En az bir büyük harf")
  .regex(/[0-9]/, "En az bir rakam");

// Sayı validasyonları (number validations)
const FiyatSemasi = z.number().positive().multipleOf(0.01);

// Dizi validasyonları (array validations)
const EtiketlerSemasi = z.array(z.string()).min(1).max(10);

// Union ve discriminated union
const BildirimSemasi = z.discriminatedUnion("tur", [
  z.object({ tur: z.literal("email"), adres: z.string().email() }),
  z.object({ tur: z.literal("sms"), telefon: z.string() }),
  z.object({ tur: z.literal("push"), token: z.string() }),
]);

// Dönüştürme (transform)
const TarihSemasi = z.string()
  .transform((s) => new Date(s))
  .refine((d) => !isNaN(d.getTime()), "Geçerli tarih giriniz");

// Default değerler (default values)
const AyarlarSemasi = z.object({
  tema: z.enum(["acik", "koyu"]).default("acik"),
  sayfa: z.number().int().positive().default(1),
  limit: z.number().int().positive().max(100).default(20),
});

React Hook Form + Zod Entegrasyonu (Integration):

bash
npm install react-hook-form @hookform/resolvers zod
tsx
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

const KayitSemasi = z.object({
  isim: z.string().min(2, "İsim gerekli"),
  email: z.string().email("Geçerli email giriniz"),
  sifre: z.string().min(8, "En az 8 karakter"),
  sifreTekrar: z.string(),
}).refine((data) => data.sifre === data.sifreTekrar, {
  message: "Şifreler eşleşmiyor",
  path: ["sifreTekrar"],
});

type KayitForm = z.infer<typeof KayitSemasi>;

function KayitFormu() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<KayitForm>({
    resolver: zodResolver(KayitSemasi),
  });

  const onSubmit = (data: KayitForm) => {
    // data burada tamamen doğrulanmış ve tip-güvenli
    // (data is fully validated and type-safe here)
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("isim")} />
      {errors.isim && <span>{errors.isim.message}</span>}

      <input {...register("email")} />
      {errors.email && <span>{errors.email.message}</span>}

      <input type="password" {...register("sifre")} />
      {errors.sifre && <span>{errors.sifre.message}</span>}

      <input type="password" {...register("sifreTekrar")} />
      {errors.sifreTekrar && <span>{errors.sifreTekrar.message}</span>}

      <button type="submit">Kayıt Ol</button>
    </form>
  );
}

Express + Zod Middleware:

typescript
import { z, type ZodSchema } from "zod";
import type { Request, Response, NextFunction } from "express";

function zodDogrula(sema: ZodSchema) {
  return (req: Request, res: Response, next: NextFunction) => {
    const sonuc = sema.safeParse(req.body);
    if (!sonuc.success) {
      return res.status(400).json({
        basarili: false,
        hatalar: sonuc.error.flatten().fieldErrors,
      });
    }
    req.body = sonuc.data;
    next();
  };
}

// Kullanım (usage)
router.post("/kullanicilar", zodDogrula(KullaniciSemasi), (req, res) => {
  // req.body burada doğrulanmış (validated here)
  res.status(201).json(req.body);
});

Summary: Zod, runtime tip doğrulaması sağlar ve z.infer ile TypeScript tipi çıkarır. safeParse hata fırlatmadan sonuç döner. React Hook Form ile entegre çalışır.


17) tsconfig.json Detaylı Rehber (Detailed Guide)

Temel Yapılandırma Alanları (Basic Configuration Fields):

json
{
  "compilerOptions": { /* derleyici seçenekleri (compiler options) */ },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"],
  "extends": "./tsconfig.base.json",
  "references": [{ "path": "./packages/shared" }]
}

strict Modu ve Alt Seçenekleri (strict Mode and Sub-options):

strict: true aşağıdaki tüm seçenekleri açar. Yeni projelerde daima true olmalı. (strict: true enables all options below. Should always be true in new projects.)

Alt Seçenek (Sub-option)Açıklama (Description)Neden Önemli (Why Important)
strictNullChecksnull/undefined ayrı tip olarak işler (treats null/undefined as separate types)null referans hatalarını önler
noImplicitAnyTip çıkarılmayan yerlerde any yasak (bans any where type can't be inferred)Farkında olmadan any kullanımını önler
strictFunctionTypesFonksiyon parametre kontravaryans kontrolü (function parameter contravariance)Yanlış fonksiyon atamalarını yakalar
strictBindCallApplybind/call/apply için tam tip kontrolü (full type checking for bind/call/apply)Runtime hatalarını derleme zamanında yakalar
strictPropertyInitializationSınıf özelliklerinin constructor'da atanması (class properties must be initialized)Uninitialized property hatalarını önler
noImplicitThisBelirsiz this kullanımını yasaklar (bans ambiguous this usage)this bağlam hatalarını önler
alwaysStrictHer JS dosyasında "use strict" ekler (adds "use strict" to every JS file)Strict mode davranışı garanti eder

paths ve baseUrl — Import Kısayolları (Import Aliases):

json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"],
      "@hooks/*": ["./src/hooks/*"],
      "@utils/*": ["./src/utils/*"],
      "@types/*": ["./src/types/*"],
      "@lib/*": ["./src/lib/*"]
    }
  }
}

Not: paths sadece TypeScript derleyicisi için çalışır. Bundler (Webpack, Vite) veya runtime (Node.js) için ayrıca yapılandırma gerekir: (Note: paths only works for the TypeScript compiler. Additional configuration is needed for bundlers or runtime.)

javascript
// vite.config.ts
import { defineConfig } from "vite";
import path from "path";

export default defineConfig({
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

target ve module Seçenekleri (Options):

Ortam (Environment)targetmodulemoduleResolution
Modern frontend (Vite/Next)ES2020ESNextbundler
Node.js (CommonJS)ES2020commonjsnode
Node.js (ESM)ES2022NodeNextnodenext
Library (universal)ES2018ESNextbundler

Ek Önemli Seçenekler (Additional Important Options):

json
{
  "compilerOptions": {
    // Tip Güvenlik — strict'e ek olarak (Type Safety — in addition to strict)
    "noUncheckedIndexedAccess": true,    // dizi/obje erişiminde T | undefined
    "noFallthroughCasesInSwitch": true,  // switch'te break unutmayı yakalar
    "exactOptionalPropertyTypes": true,  // undefined ile optional farkı

    // Modül Sistemi (Module System)
    "esModuleInterop": true,             // CommonJS default import uyumluluğu
    "resolveJsonModule": true,           // JSON import desteği
    "isolatedModules": true,             // SWC/esbuild uyumluluğu

    // Çıktı (Output)
    "declaration": true,                 // .d.ts dosyaları üret
    "declarationMap": true,              // .d.ts.map (kaynak koduna atlama)
    "sourceMap": true,                   // debug için
    "noEmit": true,                      // bundler kullanılıyorsa

    // Performans (Performance)
    "skipLibCheck": true,                // .d.ts kontrolünü atla (hız için)
    "incremental": true,                 // artımlı derleme (incremental build)
    "tsBuildInfoFile": "./.tsbuildinfo"  // derleme önbellek dosyası
  }
}

Monorepo için Project References:

json
// tsconfig.json (kök — root)
{
  "references": [
    { "path": "./packages/shared" },
    { "path": "./packages/frontend" },
    { "path": "./packages/backend" }
  ],
  "files": []
}

// packages/frontend/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "composite": true,
    "outDir": "./dist"
  },
  "references": [
    { "path": "../shared" }
  ]
}

Summary: strict: true her zaman aç. paths ile import kısayolları tanımla, bundler'da da yapılandır. noUncheckedIndexedAccess ek güvenlik sağlar.


18) Sık Yapılan Hatalar & Çözümler (Common Mistakes & Solutions)

1. any Aşırı Kullanımı (Overuse of any):

typescript
// YANLIŞ — tip güvenliğini yok eder (WRONG — destroys type safety)
function veriIsle(data: any) {
  return data.kullanici.isim.toUpperCase();
}

// DOĞRU — tip belirt veya unknown kullan (CORRECT — specify type or use unknown)
function veriIsle(data: unknown): string {
  if (
    typeof data === "object" && data !== null &&
    "kullanici" in data
  ) {
    // tip daraltma ile güvenli erişim (safe access with type narrowing)
    const kul = (data as { kullanici: { isim: string } }).kullanici;
    return kul.isim.toUpperCase();
  }
  throw new Error("Geçersiz veri formatı");
}

2. Null Kontrol Eksikliği (Missing Null Check):

typescript
// YANLIŞ — runtime'da patlar (WRONG — crashes at runtime)
const eleman = document.querySelector(".baslik");
eleman.textContent = "Merhaba"; // eleman null olabilir!

// DOĞRU (CORRECT)
const eleman = document.querySelector(".baslik");
if (eleman) {
  eleman.textContent = "Merhaba";
}

// veya optional chaining
document.querySelector(".baslik")?.setAttribute("class", "aktif");

3. Object vs object vs {} Karışıklığı (Confusion):

typescript
// Object — tüm nesneler (KAÇINILMALI — SHOULD BE AVOIDED)
// object — primitif olmayan (fonksiyon, dizi, obje) (non-primitive)
// {} — boş obje değil, any non-null değer demek (KAÇINILMALI)
// Record<string, unknown> — gerçek boş obje tipi (actual empty object type)

// DOĞRU kullanım (CORRECT usage)
function isleYap(veri: Record<string, unknown>): void {
  // ...
}

4. Enum Yerine Union Kullan (Use Union Instead of Enum):

typescript
// ENUM — gereksiz runtime kodu üretir (produces unnecessary runtime code)
enum Renk { Kirmizi, Yesil, Mavi }

// UNION — sıfır runtime maliyeti, daha iyi tip daraltma
// (zero runtime cost, better type narrowing)
type Renk = "kirmizi" | "yesil" | "mavi";

5. Type Assertion Aşırı Kullanımı (Overuse of Type Assertion):

typescript
// YANLIŞ — runtime hatası riski (WRONG — runtime error risk)
const kullanici = {} as Kullanici;
console.log(kullanici.isim.length); // runtime hata!

// DOĞRU — gerçekten oluştur (CORRECT — actually create it)
const kullanici: Kullanici = {
  id: 1,
  isim: "Fahri",
  email: "fahri@test.com"
};

6. Return Type Eksikliği (Missing Return Type) (Public API):

typescript
// YANLIŞ — dönüş tipi çıkarılır ama değişebilir
// (WRONG — return type is inferred but can change)
export function kullaniciBul(id: number) {
  // return tipi buradaki implementasyona bağımlı
  return db.kullanicilar.find((k) => k.id === id);
}

// DOĞRU — açık dönüş tipi, API sözleşmesi
// (CORRECT — explicit return type, API contract)
export function kullaniciBul(id: number): Kullanici | undefined {
  return db.kullanicilar.find((k) => k.id === id);
}

7. Interface vs Type Tutarsızlığı (Inconsistency):

typescript
// Bir kural seç ve uygula (pick a rule and apply it)
// Öneri: obje şekilleri için interface, union/intersection için type
// (Suggestion: interface for object shapes, type for union/intersection)

// Tutarlı ol (be consistent):
interface KullaniciProps { isim: string; }  // OK
interface UrunProps { ad: string; }         // OK — tutarlı (consistent)
// type KullaniciProps = { isim: string; }  // Karıştırma (mixing)

8. Generic Default Değerleri Kullanmamak (Not Using Generic Defaults):

typescript
// YANLIŞ — her seferinde tip belirtmek zorunda
// (WRONG — must specify type every time)
interface ApiYanit<T> { data: T; hata?: string; }

// DOĞRU — varsayılan tip (CORRECT — default type)
interface ApiYanit<T = unknown> { data: T; hata?: string; }
const yanit: ApiYanit = { data: "test" }; // T = unknown

Summary: any yerine unknown, null kontrolü yap, enum yerine union tercih et, public fonksiyonlarda dönüş tipi belirt.


19) Güvenlik ve Tip Riskleri (Security and Type Risks)

any Riskleri ve Kaçış Yolları (Risks of any and Escape Routes):

any tüm tip kontrollerini devre dışı bırakır. Kodun herhangi bir yerinde any varsa, o noktadan yayılarak diğer tipleri de zehirler. (any disables all type checks. If any exists anywhere in the code, it spreads from that point and poisons other types.)

typescript
// any bulaşması — bir any tüm zinciri bozar
// (any contamination — one any breaks the entire chain)
function tehlikeliVeriAl(): any {
  return JSON.parse('{"isim": 123}');
}

const kullanici = tehlikeliVeriAl();
// kullanici: any — artık isim'in string olduğunu bilmiyoruz
const uzunluk = kullanici.isim.length; // runtime'da patlar!

// Çözüm: unknown + runtime doğrulama (Solution: unknown + runtime validation)
function guvenliVeriAl(): unknown {
  return JSON.parse('{"isim": 123}');
}

const veri = guvenliVeriAl();
// Zod ile doğrula (validate with Zod)
const sonuc = KullaniciSemasi.safeParse(veri);
if (sonuc.success) {
  console.log(sonuc.data.isim); // tip-güvenli (type-safe)
}

Type Assertion Tehlikeleri (Dangers of Type Assertion):

typescript
// as ile yalan söyleyebilirsiniz — derleyici itiraz etmez
// (you can lie with as — the compiler won't object)
interface Kullanici {
  id: number;
  isim: string;
  email: string;
}

// Tehlikeli: boş obje Kullanıcı olarak işaretlendi
// (Dangerous: empty object marked as Kullanici)
const k = {} as Kullanici;
console.log(k.isim.toUpperCase()); // Runtime: Cannot read property of undefined

// Güvenli alternatif: fabrika fonksiyon (Safe alternative: factory function)
function kullaniciOlustur(
  data: Omit<Kullanici, "id">
): Kullanici {
  return { id: Date.now(), ...data };
}

@ts-ignore vs @ts-expect-error:

typescript
// @ts-ignore — sonraki satırdaki tüm hataları susturur
// (silences all errors on the next line)
// Tehlike: hata düzeltilse bile yorum kalır, gerçek hatayı gizleyebilir
// (Danger: comment remains even if error is fixed, can hide real errors)
// @ts-ignore
const x: number = "yanlis"; // hata susturuldu

// @ts-expect-error — hata BEKLER, hata yoksa UYARI verir
// (EXPECTS an error, WARNS if there's no error)
// Tercih et: hata düzeltildiğinde haberdar olursun
// (Prefer this: you'll be notified when the error is fixed)
// @ts-expect-error — bilinen API uyumsuzluğu, issue #1234
const y: number = "yanlis";

// Hata düzeltildiğinde (when the error is fixed):
// @ts-expect-error  <-- Bu satırda "Unused @ts-expect-error" uyarısı alırsın
const z: number = 42; // artık hata yok, yorumu kaldır

Runtime Validation Neden Önemli (Why Runtime Validation Matters):

TypeScript tipleri derleme sonrasında tamamen silinir. Dış kaynaklardan gelen verilere güvenemezsiniz. (TypeScript types are completely erased after compilation. You cannot trust data from external sources.)

typescript
// Bu noktalar runtime doğrulama gerektirir:
// (These points require runtime validation:)
// 1. API yanıtları (fetch, axios) — API responses
// 2. Form verileri (req.body) — Form data
// 3. URL parametreleri (req.params, req.query) — URL parameters
// 4. localStorage/sessionStorage
// 5. WebSocket mesajları — WebSocket messages
// 6. Dosya okuma (JSON.parse) — File reading
// 7. Üçüncü parti kütüphane dönüşleri — Third-party library returns

// Örnek: API yanıtı doğrulama (Example: API response validation)
async function kullanicilariGetir(): Promise<Kullanici[]> {
  const res = await fetch("/api/users");
  const json: unknown = await res.json();

  // Zod ile doğrula (validate with Zod)
  const sema = z.array(KullaniciSemasi);
  return sema.parse(json); // geçersiz veride hata fırlatır
}

ESLint Tip Kuralları (Type Rules):

bash
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin
javascript
// eslint.config.js (flat config)
export default [
  {
    rules: {
      "@typescript-eslint/no-explicit-any": "error",
      "@typescript-eslint/no-non-null-assertion": "warn",
      "@typescript-eslint/no-unsafe-assignment": "error",
      "@typescript-eslint/no-unsafe-member-access": "error",
      "@typescript-eslint/no-unsafe-return": "error",
      "@typescript-eslint/explicit-function-return-type": "warn",
      "@typescript-eslint/strict-boolean-expressions": "error",
    },
  },
];

Summary: any'den kaçın, unknown + runtime doğrulama kullan. @ts-ignore yerine @ts-expect-error tercih et. Dış veri kaynakları için mutlaka Zod benzeri doğrulama ekle.


20) JS'den TS'ye Geçiş (Migration) Stratejisi (JS to TS Migration Strategy)

Adım Adım Geçiş Planı (Step-by-Step Migration Plan):

Büyük bir JavaScript projesini tek seferde TypeScript'e çevirmek risklidir. Aşağıdaki adımlarla kademeli geçiş yapılmalı. (Converting a large JavaScript project to TypeScript all at once is risky. A gradual migration should be done with the steps below.)

1. Adım: tsconfig ile Hazırlık (Step 1: Preparation with tsconfig) (allowJs)

json
{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": false,
    "strict": false,
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "outDir": "./dist",
    "rootDir": "./src",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "noEmit": true
  },
  "include": ["src/**/*"]
}

Bu yapılandırma JS ve TS dosyalarının bir arada çalışmasını sağlar. (This configuration allows JS and TS files to coexist.)

2. Adım: JS Dosyalarını Kademeli Olarak .ts'e Çevir (Step 2: Gradually Convert JS Files to .ts)

bash
# En az bağımlılıklı dosyadan başla
# (Start from the file with the fewest dependencies)
# Öncelik sırası: utils > types > services > components > pages

# Dosya uzantısını değiştir (change file extension)
mv src/utils/helpers.js src/utils/helpers.ts

# TypeScript hatalarını kontrol et (check TypeScript errors)
npx tsc --noEmit
typescript
// helpers.js (öncesi — before)
export function formatPara(miktar) {
  return miktar.toFixed(2) + " TL";
}

// helpers.ts (sonrası — after)
export function formatPara(miktar: number): string {
  return miktar.toFixed(2) + " TL";
}

3. Adım: strict Seçeneklerini Kademeli Aç (Step 3: Gradually Enable strict Options)

json
// Hafta 1: Temel kontroller (Week 1: Basic checks)
{
  "strict": false,
  "noImplicitAny": true
}

// Hafta 2: Null kontrolleri (Week 2: Null checks)
{
  "noImplicitAny": true,
  "strictNullChecks": true
}

// Hafta 3: Fonksiyon kontrolleri (Week 3: Function checks)
{
  "noImplicitAny": true,
  "strictNullChecks": true,
  "strictFunctionTypes": true,
  "strictBindCallApply": true
}

// Hafta 4+: Tam strict (Week 4+: Full strict)
{
  "strict": true
}

4. Adım: Üçüncü Parti Tip Tanımları (Step 4: Third-Party Type Definitions)

bash
# Mevcut paketlerin tiplerini yükle (install types for existing packages)
npm install --save-dev @types/node @types/express @types/lodash

# Tipsiz paketler için .d.ts oluştur (create .d.ts for untyped packages)
# src/types/untyped-packages.d.ts
typescript
// Geçici çözüm: tipsiz paketler için (temporary solution: for untyped packages)
declare module "eski-paket";           // any olarak import edilir
declare module "yarim-tipli-paket" {   // minimum tip tanımla
  export function anaFonksiyon(x: string): void;
}

5. Adım: CI/CD Entegrasyonu (Step 5: CI/CD Integration)

json
// package.json
{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "typecheck:watch": "tsc --noEmit --watch",
    "lint": "eslint . --ext .ts,.tsx",
    "ci": "npm run typecheck && npm run lint && npm test"
  }
}

Geçiş İpuçları (Migration Tips):

  • Tüm dosyaları aynı anda çevirmeye çalışmayın, modülleri tek tek geçirin (don't convert all files at once, migrate modules one by one)
  • any ile başlayıp zamanla daraltmak kabul edilebilir bir stratejidir (starting with any and narrowing over time is acceptable)
  • Yeni kod her zaman TypeScript ile yazılmalı (new code should always be written in TypeScript)
  • Testler geçişi doğrulamak için kritik önem taşır (tests are critical for validating the migration)
  • @ts-expect-error ile bilinen sorunları işaretleyin ve issue oluşturun (mark known issues and create issues)
  • Monorepo'larda shared paketlerden başlayın (in monorepos, start with shared packages)

Summary: allowJs: true ile başlayıp dosya dosya geçiş yap. strict seçeneklerini kademeli aç. Yeni kod daima TS ile yaz.


21) TypeScript İpuçları ve En İyi Uygulamalar (Tips and Best Practices)

unknown > any Tercih Et (Prefer unknown over any):

typescript
// any — tüm tip kontrollerini devre dışı bırakır (disables all type checks)
// unknown — güvenli alternatif, kullanmadan önce daraltma gerektirir
// (safe alternative, requires narrowing before use)

function jsonParse(metin: string): unknown {
  return JSON.parse(metin);
}

const veri = jsonParse('{"x": 1}');
// veri.x; // HATA: unknown üzerinde erişim yapılmaz
if (typeof veri === "object" && veri !== null && "x" in veri) {
  console.log((veri as { x: number }).x); // OK
}

const Assertion:

typescript
// Değerleri literal tip olarak sabitle (lock values as literal types)
const DURUMLAR = ["aktif", "pasif", "beklemede"] as const;
type Durum = typeof DURUMLAR[number]; // "aktif" | "pasif" | "beklemede"

// Obje sabitleri (object constants)
const HTTP_KODLARI = {
  OK: 200,
  OLUSTURULDU: 201,
  BULUNAMADI: 404,
  SUNUCU_HATASI: 500,
} as const;

type HTTPKodu = typeof HTTP_KODLARI[keyof typeof HTTP_KODLARI];
// 200 | 201 | 404 | 500

satisfies Operatörü (satisfies Operator):

typescript
// Tipi kontrol eder AMA daha spesifik tipi korur
// (Checks the type BUT preserves the more specific type)
type Route = {
  yol: string;
  metodlar: ("GET" | "POST" | "PUT" | "DELETE")[];
};

const rotalar = {
  anasayfa: { yol: "/", metodlar: ["GET"] },
  kullanicilar: { yol: "/users", metodlar: ["GET", "POST"] },
  profil: { yol: "/profile", metodlar: ["GET", "PUT"] },
} satisfies Record<string, Route>;

// TypeScript her rotanın spesifik tipini biliyor
// (TypeScript knows the specific type of each route)
rotalar.anasayfa.metodlar; // readonly ["GET"] — sadece "GET" içerdiğini biliyor

Discriminated Unions ile Durum Yönetimi (State Management with Discriminated Unions):

typescript
// State machine pattern
type YuklemeState<T> =
  | { durum: "bosta" }
  | { durum: "yukleniyor" }
  | { durum: "basarili"; veri: T }
  | { durum: "hata"; mesaj: string; kod?: number };

function durumIsle<T>(state: YuklemeState<T>): string {
  switch (state.durum) {
    case "bosta":
      return "Henüz başlamadı";
    case "yukleniyor":
      return "Yükleniyor...";
    case "basarili":
      return `Veri: ${JSON.stringify(state.veri)}`;
    case "hata":
      return `Hata: ${state.mesaj}`;
  }
}

Utility Types İleri Kullanım (Advanced Usage):

typescript
// DeepPartial — iç içe tüm alanları opsiyonel yapar
// (makes all nested fields optional)
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// DeepReadonly — iç içe tüm alanları readonly yapar
// (makes all nested fields readonly)
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

// Mutable — Readonly'i geri alır (reverses Readonly)
type Mutable<T> = {
  -readonly [P in keyof T]: T[P];
};

// RequiredKeys — sadece zorunlu alanları çıkar (extracts only required keys)
type RequiredKeys<T> = {
  [K in keyof T]-?: {} extends Pick<T, K> ? never : K;
}[keyof T];

// OptionalKeys — sadece opsiyonel alanları çıkar (extracts only optional keys)
type OptionalKeys<T> = {
  [K in keyof T]-?: {} extends Pick<T, K> ? K : never;
}[keyof T];

Brand Types — Tip Karıştırmayı Önle (Prevent Type Confusion):

typescript
// Aynı primitif tipte ama farklı anlamda değerleri ayırt et
// (Distinguish values with same primitive type but different meaning)
type KullaniciId = number & { readonly __brand: "KullaniciId" };
type SiparisId = number & { readonly __brand: "SiparisId" };

function kullaniciIdOlustur(id: number): KullaniciId {
  return id as KullaniciId;
}

function siparisIdOlustur(id: number): SiparisId {
  return id as SiparisId;
}

function kullaniciBul(id: KullaniciId): void { /* ... */ }
function siparisBul(id: SiparisId): void { /* ... */ }

const uid = kullaniciIdOlustur(1);
const oid = siparisIdOlustur(1);

kullaniciBul(uid); // OK
// kullaniciBul(oid); // HATA: SiparisId, KullaniciId'ye atanamaz

Tip-Güvenli Event Emitter (Type-Safe Event Emitter):

typescript
type EventMap = {
  kullaniciGirisi: { kullaniciId: string; zaman: Date };
  kullaniciCikisi: { kullaniciId: string };
  hata: { mesaj: string; kod: number };
};

class TipliEventEmitter<T extends Record<string, unknown>> {
  private dinleyiciler = new Map<keyof T, Set<(veri: any) => void>>();

  on<K extends keyof T>(olay: K, fn: (veri: T[K]) => void): void {
    if (!this.dinleyiciler.has(olay)) {
      this.dinleyiciler.set(olay, new Set());
    }
    this.dinleyiciler.get(olay)!.add(fn);
  }

  emit<K extends keyof T>(olay: K, veri: T[K]): void {
    this.dinleyiciler.get(olay)?.forEach((fn) => fn(veri));
  }
}

const emitter = new TipliEventEmitter<EventMap>();
emitter.on("kullaniciGirisi", (veri) => {
  console.log(veri.kullaniciId); // tip-güvenli (type-safe)
});

Summary: unknown > any, as const ile literal tipler, satisfies ile tip kontrolü, discriminated union ile durum yönetimi, brand types ile tip karıştırmayı önle.


22) TypeScript ile Test Yazma (Writing Tests with TypeScript)

Vitest + TypeScript Kurulumu (Setup):

bash
npm install --save-dev vitest @vitest/coverage-v8
typescript
// vitest.config.ts
import { defineConfig } from "vitest/config";
import path from "path";

export default defineConfig({
  test: {
    globals: true,
    environment: "node",
    include: ["src/**/*.test.ts", "src/**/*.spec.ts"],
    coverage: {
      provider: "v8",
      reporter: ["text", "html"],
      include: ["src/**/*.ts"],
      exclude: ["src/**/*.test.ts", "src/**/*.d.ts"],
    },
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

Temel Test Örnekleri (Basic Test Examples):

typescript
// src/utils/hesapla.ts
export function topla(a: number, b: number): number {
  return a + b;
}

export function bol(a: number, b: number): number {
  if (b === 0) throw new Error("Sıfıra bölme hatası");
  return a / b;
}

// src/utils/hesapla.test.ts
import { describe, it, expect } from "vitest";
import { topla, bol } from "./hesapla";

describe("topla", () => {
  it("iki pozitif sayıyı toplar", () => {
    expect(topla(2, 3)).toBe(5);
  });

  it("negatif sayılarla çalışır", () => {
    expect(topla(-1, -2)).toBe(-3);
  });
});

describe("bol", () => {
  it("doğru bölme yapar", () => {
    expect(bol(10, 2)).toBe(5);
  });

  it("sıfıra bölmede hata fırlatır", () => {
    expect(() => bol(10, 0)).toThrow("Sıfıra bölme hatası");
  });
});

Mock Tiplendirme (Mock Typing):

typescript
import { describe, it, expect, vi, type Mock } from "vitest";

// Fonksiyon mock'u (function mock)
interface KullaniciServisi {
  getir(id: number): Promise<Kullanici>;
  kaydet(kullanici: Kullanici): Promise<void>;
}

const mockServis: KullaniciServisi = {
  getir: vi.fn<[number], Promise<Kullanici>>().mockResolvedValue({
    id: 1,
    isim: "Test",
    email: "test@test.com",
  }),
  kaydet: vi.fn<[Kullanici], Promise<void>>().mockResolvedValue(undefined),
};

// Modül mock'u (module mock)
vi.mock("./api", () => ({
  kullaniciGetir: vi.fn<[number], Promise<Kullanici>>(),
}));

// Mock'un çağrıldığını doğrula (verify mock was called)
describe("KullaniciServisi", () => {
  it("kullanıcıyı getirir", async () => {
    const kullanici = await mockServis.getir(1);
    expect(kullanici.isim).toBe("Test");
    expect(mockServis.getir).toHaveBeenCalledWith(1);
  });
});

Type Testing — tsd ve expect-type:

Tiplerin doğru çalıştığını test etmek için expect-type kullanılır. (Use expect-type to test that types work correctly.)

bash
npm install --save-dev expect-type
typescript
// src/types.test-d.ts
import { expectTypeOf } from "expect-type";
import type { ApiYanit, Kullanici } from "./types";

// Tipin doğru şekilde çıkarıldığını test et
// (Test that the type is correctly inferred)
expectTypeOf<ApiYanit<Kullanici>>().toMatchTypeOf<{
  data: Kullanici;
  basarili: boolean;
}>();

// Fonksiyon dönüş tipini test et (test function return type)
declare function kullaniciGetir(id: number): Promise<Kullanici>;

expectTypeOf(kullaniciGetir).parameter(0).toBeNumber();
expectTypeOf(kullaniciGetir).returns.resolves.toMatchTypeOf<Kullanici>();

// Generic tipin doğru çalıştığını test et
// (Test that the generic type works correctly)
type Nullable<T> = T | null;
expectTypeOf<Nullable<string>>().toEqualTypeOf<string | null>();

// Atanamaz olması gereken durumlar (cases that should not be assignable)
expectTypeOf<string>().not.toEqualTypeOf<number>();
expectTypeOf<{ a: string }>().not.toMatchTypeOf<{ b: number }>();

CI/CD için TypeScript Kontrolleri (TypeScript Checks for CI/CD):

json
// package.json
{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:coverage": "vitest run --coverage",
    "test:types": "vitest typecheck",
    "ci": "npm run typecheck && npm run lint && npm run test:coverage"
  }
}
yaml
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx tsc --noEmit          # tip kontrolü (type check)
      - run: npm run lint               # lint kontrolü
      - run: npm run test:coverage      # testler + kapsam (tests + coverage)

tsc --noEmit Neden Önemli (Why tsc --noEmit Matters):

tsc --noEmit komutu JS çıktısı üretmeden tip kontrolü yapar. Bu, CI/CD'de hızlı geri bildirim için idealdir. (tsc --noEmit performs type checking without producing JS output. Ideal for quick feedback in CI/CD.)

bash
# Sadece tip kontrolü — dosya üretmez (type check only — no files produced)
npx tsc --noEmit

# Belirli dosyayı kontrol et (check specific file)
npx tsc --noEmit src/utils/helpers.ts

# Hataları ayrıntılı göster (show errors in detail)
npx tsc --noEmit --pretty

Summary: Vitest ile TS testleri yaz. expect-type ile tip testleri ekle. CI'da tsc --noEmit ile tip kontrolü yap. Mock'ları tiplendir.


23) Hızlı Referans Tablosu (Quick Reference Table)

Tip Tanımlama (Type Definitions):

typescript
// Primitif tipler (primitive types)
let s: string;        let n: number;       let b: boolean;
let u: undefined;     let nl: null;        let sym: symbol;
let big: bigint;

// Dizi ve Tuple (Array and Tuple)
let arr: number[];    let tup: [string, number];

// Obje (Object)
let obj: { a: string; b?: number };

// Fonksiyon (Function)
let fn: (x: number) => string;

// Union ve Intersection
let uni: string | number;
let inter: A & B;

Yaygın Kalıplar (Common Patterns):

typescript
// Nullable tip (nullable type)
type Nullable<T> = T | null;

// Async fonksiyon dönüş tipi (async function return type)
type AsyncFn<T> = () => Promise<T>;

// DeepPartial — iç içe opsiyonel (deeply optional)
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// DeepReadonly — iç içe değiştirilemez (deeply immutable)
type DeepReadonly<T> = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

// Enum benzeri const object (enum-like const object)
const DURUMLAR = {
  AKTIF: "aktif",
  PASIF: "pasif",
  BEKLEMEDE: "beklemede"
} as const;
type Durum = typeof DURUMLAR[keyof typeof DURUMLAR];

// Tip-güvenli Object.keys (type-safe Object.keys)
function anahtarlar<T extends object>(obj: T): (keyof T)[] {
  return Object.keys(obj) as (keyof T)[];
}

React Tip Referansı (React Type Reference):

tsx
// Component Props
interface Props { children: React.ReactNode; }

// Event Types
React.MouseEvent<HTMLButtonElement>
React.ChangeEvent<HTMLInputElement>
React.FormEvent<HTMLFormElement>
React.KeyboardEvent<HTMLInputElement>

// Hook Return Types
useState<T>() → [T, React.Dispatch<React.SetStateAction<T>>]
useRef<T>(null) → React.RefObject<T>
useRef<T>(value) → React.MutableRefObject<T>

// Context
createContext<T | null>(null) + custom hook

Sık Kullanılan tsconfig Ayarları (Commonly Used tsconfig Settings):

json
{
  "compilerOptions": {
    "strict": true,
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "paths": { "@/*": ["./src/*"] }
  }
}

Tip Daraltma (Narrowing) Yöntemleri (Type Narrowing Methods):

Yöntem (Method)Örnek (Example)Kullanım (Usage)
typeoftypeof x === "string"Primitif tipler
instanceofx instanceof DateSınıf örnekleri (class instances)
in"isim" in xObje özellikleri (object properties)
Array.isArrayArray.isArray(x)Dizi kontrolü (array check)
Discriminated unionx.tur === "daire"Etiketli union'lar (tagged unions)
Custom guardfunction isX(v): v is XKarmaşık kontroller (complex checks)
satisfiesx satisfies TTip uyumluluk kontrolü (type compatibility check)

Utility Types Hızlı Referans (Quick Reference):

UtilityGirdi (Input)Çıktı (Output)
Partial<{a:string}>{a:string}{a?:string}
Required<{a?:string}>{a?:string}{a:string}
Readonly<{a:string}>{a:string}{readonly a:string}
Pick<{a:s,b:n},"a">{a:s,b:n}{a:s}
Omit<{a:s,b:n},"a">{a:s,b:n}{b:n}
Record<string,number>K,V{[k:string]:number}
Exclude<"a"|"b","a">union"b"
Extract<"a"|"b","a">union"a"
NonNullable<s|null>nullablestring
ReturnType<()=>s>fn typestring
Parameters<(a:s)=>v>fn type[a:string]
Awaited<Promise<s>>promisestring

Bu rehber, TypeScript'in pratik kullanımını kapsayan bir referans dokümanıdır.
Her bölümü kendi projenize uygulayarak öğrenmeniz tavsiye edilir.
(This guide is a practical reference for TypeScript. Apply each section to your own projects to learn effectively.)


Frontend

Diğer Kategoriler (Other Categories)

Developer Guides & Technical References