JavaScript dinamik olarak yazılmıştır; bu gerçekten kullanışlıdır — hızlı yineleyebilir, özgürce prototip oluşturabilir ve bir derleme adımı olmadan yayınlayabilirsiniz. Ancak bu esnekliğin bir bedeli vardır: bir hata sınıfının tamamı yalnızca çalışma zamanında ortaya çıkar. Bir fonksiyon string bekler, undefined alır ve uygulamanız gece 2'de prodüksiyonda patlar. TypeScript, JavaScript'in üzerine tam olarak bu hataları derleme zamanında, düzenleyicinizde, herhangi bir şey yayınlanmadan önce yakalayan bir statik tür sistemi ekler. Bu makale bunun pratikte ne anlama geldiğini açıklar — gerçek kod, dürüst ödünleşimler ve abartı yok.

TypeScript Gerçekte Nedir

TypeScript, JavaScript'in bir üst kümesidir: her geçerli .js dosyası aynı zamanda geçerli .ts'dir. Bir dosyayı yeniden adlandırabilir, sıfır tür ek açıklaması ekleyebilirsiniz ve düzgün derlenir. TypeScript'in eklediği şeyler — tür ek açıklamaları, arayüzler, genericler, enumlar — derleme zamanında tamamen kaldırılır. Çıktı saf JavaScript'tir. TypeScript neyin çalıştığını değiştirmez; çalıştırılmadan önce bilebileceklerinizi değiştirir.

Derleyici tsc'dir ve npm aracılığıyla kurulur. Onu .ts dosyalarınıza yönlendirirsiniz ve çalışma zamanınızın (Node.js, bir tarayıcı, Deno) çalıştırabileceği .js dosyaları üretir. TypeScript'e özgü hiçbir sözdizimi üretime hiçbir zaman ulaşmaz — türler yalnızca geliştirici ve araç zinciri için vardır. GitHub'daki TypeScript deposu kendisi büyük bir TypeScript projesidir ve bu size nasıl ölçeklendiğine dair bir fikir verir.

bash
# Compile a single file
npx tsc src/index.ts

# Compile a whole project (uses tsconfig.json)
npx tsc

# Watch mode — recompile on every save
npx tsc --watch

Temel Fayda: Çalışma Zamanından Önce Hatalar

İşte TypeScript'in en görünür şekilde çözdüğü sorun. Bir alanın string veya null olabileceği bir API yanıtıyla çalıştığınızı hayal edin. Saf JavaScript'te bu, üretime kadar sessizce başarısız olur:

js
// JavaScript — no error until this actually runs with a null value
function formatDisplayName(user) {
  return user.displayName.toUpperCase(); // 💥 TypeError if displayName is null
}

// This looks fine in isolation. The bug only appears when a user
// has no display name set — which might be rare, but it will happen.
const name = formatDisplayName({ displayName: null });

TypeScript bunu kod çalıştırılmadan önce yakalar:

ts
interface User {
  id: number;
  displayName: string | null;
  email: string;
}

function formatDisplayName(user: User): string {
  return user.displayName.toUpperCase();
  // ❌ TypeScript error: Object is possibly 'null'.
  //    Property 'toUpperCase' does not exist on type 'null'.
}

// Fix: handle the null case explicitly
function formatDisplayName(user: User): string {
  if (user.displayName === null) {
    return user.email; // fall back to email
  }
  return user.displayName.toUpperCase(); // TypeScript now knows this is safe
}

Bu çoğu geliştirici için "aha" anıdır. Hata mesajı size tam olarak neyin yanlış olduğunu ve nerede olduğunu söyler — düzenleyicinizde, tek bir satır çalıştırmadan önce. strict modu etkinleştirildiğinde, TypeScript strict modda varsayılan olarak açık olan strictNullChecks özelliği aracılığıyla null ve undefined sorunlarını yakalamada özellikle agresiftir.

İçselleştirilecek desen: TypeScript hataları derleme zamanındadır, çalışma zamanında değil. tsc'den gelen bir hata, kodunuzun bir tür tutarsızlığına sahip olduğu anlamına gelir — TypeScript çalıştırmadan başarısız olacağını (veya olabileceğini) kanıtlayabilir. Tür hatasını düzeltin ve hata sınıfını tamamen ortadan kaldırmış olursunuz.

TypeScript'in Tür Sistemine Genel Bakış

Her şeyi açıklama eklemeniz gerekmez. TypeScript atamalardan, dönüş değerlerinden ve fonksiyon çağrılarından türleri çıkarır — çoğu zaman sadece normal JavaScript yazarsınız ve ücretsiz olarak tür denetimi alırsınız. Ancak çıkarım yeterli olmadığında açıklama sözdizimini bilmek yardımcı olur.

ts
// Primitives
const productName: string  = 'Wireless Keyboard';
const price:       number  = 79.99;
const inStock:     boolean = true;

// TypeScript infers these without annotations — same effect
const productName = 'Wireless Keyboard'; // inferred: string
const price       = 79.99;               // inferred: number

// Arrays
const tags:     string[]  = ['electronics', 'peripherals'];
const ratings:  number[]  = [4.5, 4.8, 4.2];

// Objects with interfaces
interface Product {
  id:          number;
  name:        string;
  price:       number;
  category:    string;
  inStock:     boolean;
  description: string | null; // union type — string or null
}

// Union types — a value that could be one of several types
type Status = 'active' | 'inactive' | 'pending'; // string literal union
type ID     = string | number;                    // string or number

// Function with typed parameters and return type
function formatProductCard(product: Product): string {
  const stockLabel = product.inStock ? 'In Stock' : 'Out of Stock';
  const desc       = product.description ?? 'No description available';
  return `${product.name} — $${product.price.toFixed(2)} (${stockLabel})
${desc}`;
}

// Generic function — works with any type, preserves it
function firstOrDefault<T>(items: T[], fallback: T): T {
  return items.length > 0 ? items[0] : fallback;
}

const first = firstOrDefault(['a', 'b', 'c'], 'z'); // inferred: string
const num   = firstOrDefault([1, 2, 3],       0);   // inferred: number

TypeScript el kitabı tür sistemi üzerinde derinlemesine gider — gerçekten iyi yazılmıştır ve temellere hakim olduğunuzda okunmaya değerdir.

Bir Projede TypeScript Kurulumu

TypeScript'i bir projeye eklemek yaklaşık beş dakika sürer. Derleyiciyi bir geliştirme bağımlılığı olarak kurarsınız, bir yapılandırma dosyası oluşturursunuz ve .js dosyalarını mantıklı olan hızda .ts olarak yeniden adlandırmaya başlarsınız.

bash
# Install TypeScript as a dev dependency
npm install -D typescript

# Generate tsconfig.json with sensible defaults
npx tsc --init

Oluşturulan tsconfig.json'un çoğu yorumlanmış onlarca seçeneği vardır. Bilmeniz gereken temel olanlar:

json
{
  "compilerOptions": {
    "target": "ES2020",       // what JavaScript version to output
    "module": "commonjs",     // module system (commonjs for Node, ESNext for bundlers)
    "outDir": "./dist",       // where compiled .js files go
    "rootDir": "./src",       // where your .ts source files live
    "strict": true,           // enables all strict type checks — highly recommended
    "esModuleInterop": true,  // smoother interop with CommonJS modules
    "skipLibCheck": true      // skip type checks on .d.ts files in node_modules
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Yeni bir projede her zaman strict: true'yu etkinleştirin. strictNullChecks, noImplicitAny ve strictFunctionTypes dahil olmak üzere çeşitli kontrolleri bir araya getirir. Mevcut bir kod tabanında bunları kademeli olarak etkinleştirmeniz gerekebilir — ancak greenfield için her şeyin başlangıcında strict olun.

TypeScript vs JavaScript — Gerçek Ödünleşimler

TypeScript'in birçok gerçek avantajı vardır, ancak gerçek maliyetleri de vardır. İşte dürüst bir değerlendirme:

  • Gerçekten çalışan otomatik tamamlama. Düzenleyiciniz her nesnenin şeklini bilir, bu nedenle tahmin etmek yerine doğru özellik adlarını ve yöntem imzalarını önerebilir. Bu tek başına her gün zaman kazandırır.
  • Prodüksiyona ulaşmadan önce yakalanan hatalar. Null dereferences, yanlış argüman türleri, eksik gerekli özellikler — TypeScript bunları yazma zamanında, gece 3'te bir olay kanalında değil işaretler.
  • Daha güvenli refactoring. Bir arabirimde bir alanı yeniden adlandırın ve TypeScript hemen güncellenmesi gereken her çağrı sitesini işaretler. Büyük bir JavaScript kod tabanında bu tür bir değişiklik korkutucudur.
  • Kod kendini belgeler. sendEmail(to: string, subject: string, body: string, options?: EmailOptions): Promise<SendResult> gibi bir fonksiyon imzası uygulamayı okumadan ihtiyacınız olan her şeyi söyler.
  • Takımlar için daha iyi. Birden fazla geliştirici bir kod tabanını paylaştığında, türler modüller arasında bir sözleşme oluşturur. Kodunuzu refactor edebilirsiniz ve meslektaşınızınkini bozmadan.

Ve dürüst maliyetler:

  • Bir derleme adımı ekler. Küçük bir script veya hızlı bir prototip için, test etmeden önce tsc çalıştırmak gerçek bir sürtüşmedir. Vanilla JavaScript anında çalışır.
  • İlk kurulum zaman alır. tsconfig.json'ı yapılandırmak, üçüncü taraf kütüphaneler için tür tanımlamaları eklemek (@types/express, vb.) ve düzenleyicinizi doğru şekilde yapılandırmak birkaç saatlik iştir.
  • any her şeyi baltalıyor. TypeScript'in bir kaçış yolu vardır — herhangi bir şeyi any olarak yazabilirsiniz, bu da o değer için tür denetimini devre dışı bırakır. any'nin aşırı kullanımı, güvenlik olmadan TypeScript'in sürtüşmesini almanız anlamına gelir. Bu bir koltuk değneği, çözüm değil.
  • Üçüncü taraf kütüphane türleri geride kalabilir. Her npm paketi TypeScript tanımları içermez. Bazıları eksik veya güncel olmayan topluluk tarafından sürdürülen @types/* paketlerine dayanır.
Vanilla JS'nin yeterli olduğu durumlar: küçük bir CLI scripti, tek seferlik bir veri geçişi, atacağınız bir hafta sonu prototipi. TypeScript'in değeri proje ve takım boyutuyla birleşir. Bir geliştirici tarafından kullanılan 200 satırlık bir scriptin türlere ihtiyacı yok. Sekiz geliştirici tarafından paylaşılan 50.000 satırlık bir kod tabanının kesinlikle ihtiyacı var.

TypeScript'nin Gerçekten Parladığı Yerler

TypeScript en büyük getiriyi üç durumda sağlar: büyük kod tabanları, paylaşılan kütüphaneler ve zaman içinde refactor edilecek her şey. Tür sistemi, yorumlar veya README dosyalarının aksine her zaman güncel olan canlı belgeler olarak işlev görür.

Pratik bir örnek: uygulamanız kullanıcı verisi döndüren bir REST API çağırıyor. TypeScript olmadan, API'nin beklediğinizi döndüreceğine güveniyorsunuz. TypeScript ile yanıtı modeller ve bir şey eşleşmediğinde anında geri bildirim alırsınız:

ts
interface ApiUser {
  id:        number;
  username:  string;
  email:     string;
  avatarUrl: string | null;
  createdAt: string; // ISO 8601 date string
  role:      'admin' | 'editor' | 'viewer';
}

interface ApiResponse<T> {
  data:    T;
  total:   number;
  page:    number;
  perPage: number;
}

async function fetchUsers(page: number): Promise<ApiResponse<ApiUser[]>> {
  const response = await fetch(`/api/users?page=${page}`);
  if (!response.ok) {
    throw new Error(`Failed to fetch users: ${response.status}`);
  }
  return response.json() as Promise<ApiResponse<ApiUser[]>>;
}

// Now every consumer of this function knows exactly what they'll get
const result = await fetchUsers(1);
result.data.forEach(user => {
  // TypeScript knows user.role is 'admin' | 'editor' | 'viewer'
  // It will error if you try to access a property that doesn't exist
  console.log(`${user.username} (${user.role})`);
});

Tür denetimini geçici olarak devre dışı bırakmanız gerektiğinde, any yerine unknown kullanın. Fark şu: any tüm kontrolleri sessizce atlar, unknown ise değeri kullanmadan önce türü daraltmanızı zorunlu kılar — güvenliği tamamen kaybetmeden kaçış yolunu alırsınız.

ts
// ❌ any — TypeScript trusts you completely, no checks
function processData(data: any) {
  data.nonExistentMethod(); // no error — TypeScript looks away
}

// ✅ unknown — you have to prove what it is before using it
function processData(data: unknown) {
  if (typeof data === 'string') {
    console.log(data.toUpperCase()); // safe — TypeScript knows it's a string here
  } else if (Array.isArray(data)) {
    console.log(data.length);        // safe — TypeScript knows it's an array
  }
}

TypeScript Playground, bu desenlerle deneme yapmanın en hızlı yoludur. Kodu yapıştırın, derlenmiş JavaScript çıktısını ve tür hatalarını gerçek zamanlı olarak görün — kurulum gerekmez.

Sonuç

TypeScript sihir değildir ve her proje için doğru değildir. Ancak büyüyen, birden fazla kişi tarafından sürdürülen veya refactor edilecek herhangi bir JavaScript kod tabanı için — geliştirme deneyimini gerçekten değiştirir. Tür sistemi, çalışma zamanı hatalarının tüm bir kategorisini yayınlanmadan önce yakalar, otomatik tamamlamayı gerçekten kullanışlı hale getirir ve refactoring'i riskli bir manuel süreçten araç zincirinin hallettiği bir şeye dönüştürür.

Başlamak için resmi TypeScript belgelerine bakın — iyi yapılandırılmış ve başlangıç dostudur. TypeScript Playground herhangi bir kurulum olmadan deneme yapmak için harikadır. MDN TypeScript sözlük girişi ikinci bir perspektif istiyorsanız sağlam bir tek sayfalık genel bakıştır. TypeScript'te JSON verileriyle çalışıyorsanız, bu sitedeki JSON to TypeScript aracı, herhangi bir JSON yükünden doğrudan TypeScript arayüzleri üretir — bir API yanıtını hızlıca modellemek istediğinizde kullanışlıdır.