czay.dev/academy
Bölüm 017 dk

TypeScript nedir, neden var?

TypeScript JavaScript'in superset'i, ama "ne demek" diyenler için somut cevaplar. Dosya tipleri, tsc, IDE leverage, structural typing ve ilk type annotation'ı yazıyoruz.

TypeScript hakkında konuşulurken çoğu junior'ın kafasında üç soru oluyor: "JavaScript'i nasıl değiştiriyor", "neden runtime'a etkisi yok deniyor", "type yazınca ne kazanıyorum"? Bu bölümün sonunda her üçüne de net cevabın olacak.

TypeScript nedir?

TypeScript, JavaScript'in superset'i olan bir dildir — her geçerli JavaScript kodu aynı zamanda geçerli TypeScript kodudur. Üzerine eklenen şey statik tip sistemi.

// Bu hem JS hem TS — geçerli
function greet(name) {
  return "Merhaba, " + name;
}
 
// Bu sadece TS — type annotation eklendi
function greet(name: string): string {
  return "Merhaba, " + name;
}

Annotation'ları kaldırırsan kod yine çalışır — TypeScript "ekler" şeyleri eklemez, sadece var olan kodu çıplak bırakır. Compile sonrası tipler silinir, browser/Node JavaScript çalıştırır.

Neden var? — JavaScript'in 3 ağrısı

1. Sessiz hatalar

JavaScript çoğu hatayı runtime'da verir. Yanlış tip geçirsen:

function divide(a, b) {
  return a / b;
}
 
divide("10", 2);   // "5" — string division, garip ama crash etmez
divide(10);        // NaN — undefined ile bölme
divide();          // NaN

Production'da bir kullanıcı "5" string'i, bir başkası NaN yiyor. Hata yakalanana kadar görünmez — log'lara bakman gerek.

TypeScript ile:

function divide(a: number, b: number): number {
  return a / b;
}
 
divide("10", 2);
// ^^^ Compile error: Argument of type 'string' is not assignable to parameter of type 'number'.
 
divide(10);
// ^^^ Compile error: Expected 2 arguments, but got 1.

Hata derleme zamanında yakalanır — kod bilgisayarına ulaşmadan.

2. IDE körlüğü

IDE'in ne tip nereden geldi bilmiyorsa autocomplete vermez. Plain JS'te:

function getUser() {
  return fetch("/api/user").then((r) => r.json());
}
 
const user = await getUser();
user.???  // IDE: bilmiyorum, herhangi bir şey olabilir

TypeScript ile:

type User = { id: string; name: string; email: string };
 
async function getUser(): Promise<User> {
  const r = await fetch("/api/user");
  return r.json();
}
 
const user = await getUser();
user.??? // IDE: id, name, email — autocomplete dolu

Saatlerce kazandırır. "Hangi field'lardı bu objede" sorusunu sürekli sormamak için TypeScript yeter.

3. Refactor korkusu

Plain JS'te 50 dosyaya yayılmış bir property'i rename etmek korkutucu. "Hepsi yakalanmadıysa runtime'da undefined" derdine düşersin. TypeScript'te User.emailUser.emailAddress rename ettiğinde her kullanım yeri otomatik güncellenir, kaçanlar compile error verir.

Yapısal tipleme — JavaScript dünyasının doğal yansıması

TypeScript "nominal" değil "structural" tip sistemi kullanır. Yani "isim aynı mı" değil "şekli aynı mı" sorulur.

type Point = { x: number; y: number };
 
function distance(p: Point) {
  return Math.sqrt(p.x ** 2 + p.y ** 2);
}
 
// Bu obje "Point" değil ama Point şeklinde — kabul edilir
const myPoint = { x: 3, y: 4, z: 5 };
distance(myPoint); // ✓ OK — extra "z" zarar vermez

JavaScript'te zaten "duck typing" mantığı var (eğer ördek gibi yürüyorsa, ördektir). TypeScript bu mantığı tip sistemine taşır — JavaScript ile uyumlu, "kütüphane" yazarken esnek.

TypeScript çalışma akışı

src/                                       dist/
├── index.ts                               ├── index.js
└── lib/util.ts        →  tsc derleme  →   └── lib/util.js
                            (tipler silinir)
 
                        veya
 
src/index.ts          →  Next.js / Vite     (transpile sırasında JS'e dönüştürür)
                         (build pipeline)

İki seçenek:

  1. tsc (TypeScript Compiler) — manuel .ts.js derleme, library'ler için
  2. Build tool integration — Next.js, Vite, esbuild, swc — TS'i transparent şekilde JavaScript'e çevirir, tsc sadece type check eder

Modern Next.js projesinde sen direkt .ts veya .tsx yazarsın, build pipeline transpile eder. tsc --noEmit sadece type check için çalışır (kod üretmez).

Kurulum — sıfırdan TypeScript

Yeni bir TypeScript projesi:

mkdir my-ts-project
cd my-ts-project
npm init -y
npm install -D typescript @types/node tsx
npx tsc --init

npx tsc --init tsconfig.json üretir — TypeScript'in compiler ayarları. Aşağıdaki gibi başlat:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "esnext",
    "moduleResolution": "bundler",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "resolveJsonModule": true,
    "noEmit": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

Önemli flag'ler:

  • strict: true — tüm strict mode kontrollerini açar (en önemli flag). Junior projeler bunu kapatır, sonra "TS bana yardım etmiyor" der. Açıkçası açık tutmak şart.
  • noUncheckedIndexedAccessarr[5] kullandığında TS sana T | undefined der, runtime'da undefined gelirsin sürpriz olmaz.
  • isolatedModules — Babel/swc gibi tool'larla uyum.
  • noEmittsc .js üretmesin, sadece type check yapsın (Next.js zaten transpile ediyor).

İlk dosya:

// src/index.ts
function greet(name: string): string {
  return `Merhaba, ${name}`;
}
 
console.log(greet("Furkan"));

Çalıştır:

npx tsx src/index.ts
# Merhaba, Furkan

tsx TypeScript'i runtime'da transpile edip Node ile çalıştırır — geliştirme için ideal. Production'da pipeline (Next.js / esbuild / swc) build sırasında transpile eder.

İlk type hatasını gör

Bir hata yapalım:

function greet(name: string): string {
  return "Merhaba, " + name.toUpperCase();
}
 
greet(42);
//    ^^ Argument of type 'number' is not assignable to parameter of type 'string'.

tsc --noEmit çalıştır:

npx tsc --noEmit
# src/index.ts:5:7 - error TS2345

Hata derleme zamanında — kodun çalışmadan önce yakalandı.

VSCode (veya başka modern IDE) bu hatayı siz yazarken kırmızı çizgiyle gösterir. npx tsc çalıştırmana bile gerek yok — IDE arka planda TypeScript'i çalıştırır.

Type yazmadan da çalışır — "infer" gücü

Her değişkene type yazmak zorunda değilsin. TypeScript çoğu zaman çıkarır (infer):

const message = "Merhaba"; // type otomatik: "Merhaba" (literal)
const count = 42;          // type otomatik: number
const items = [1, 2, 3];   // type otomatik: number[]
 
function double(x: number) {
  return x * 2;            // return type otomatik: number
}

Modern TypeScript'te gereksiz annotation yazma — TS'in çıkarımına güven. Anotation'ı sadece API sınırı olarak yaz:

  • Fonksiyon parametre tipleri (caller bilmeli)
  • Public function return type'ı (kontrat netleşsin)
  • Interface/type alias (paylaşılan kontrat)
// ✓ İyi — parametre annotated
function getUserName(user: User): string {
  return user.name; // return inferred
}
 
// ✗ Gereksiz — TS zaten infer ediyor
function getUserName(user: User): string {
  const name: string = user.name; // : string fazla
  return name;
}

Az annotation = kısa kod = daha az gürültü. TypeScript "yardımcı", "baş ağrısı" değil.

Önemli: "any" kaçışı

TypeScript'te any tip sisteminden çıkış kapısıdır. Her şeye uyar, hiçbir şeyi kontrol etmez:

const x: any = "merhaba";
x.toUpperCase();    // OK
x();                // OK
x.foo.bar.baz;      // OK — runtime'da patlar

Yeni başlayan TS dev'inin en sık yaptığı hata: hata aldı, any yapıştırıp geçti. Bu, TypeScript'in tüm sebebini yok eder.

any yerine ne yapalım?

  • Tip belli değilse unknown kullan — tip kontrolü yapmadan kullanamazsın
  • 3rd party library tip yoksa @types/... paketi yükle veya kendi yaz
  • Kodun tipini gerçekten bilmiyorsan, bilmek için bir-iki dakika harca — bu yatırım hayatını kurtarır

tsconfig.json'da:

{
  "compilerOptions": {
    "noImplicitAny": true  // (strict: true ile zaten açık)
  }
}

any yazmaman için eslint kuralı:

// eslint.config.js
"@typescript-eslint/no-explicit-any": "error"

Açık any kullanırsan lint hatası — production projelerde kural.

Bu bölümün özeti

Bu bölümde:

  1. TypeScript nedir — JavaScript superset'i, statik tip sistemi ekler, runtime'a inmez
  2. JavaScript'in 3 ağrısı: sessiz hatalar, IDE körlüğü, refactor korkusu — TypeScript bunları çözer
  3. Yapısal tipleme — şekil önemli, isim değil
  4. Çalışma akışıtsc veya build tool integration, modern projelerde Next.js/Vite/esbuild transpile eder
  5. Kurulumtsc --init, tsconfig.json, strict: true öneri
  6. İlk dosya — annotation, tsx ile çalıştırma
  7. Inference gücü — gereksiz annotation yazma, sadece API sınırlarında
  8. any tehlikesi — kullanma, unknown veya gerçek tipi bul

Sonraki bölümde temel tipleri detaylı işleyeceğiz: string, number, boolean'dan tuple, object, function, void, never, literal type'lara kadar TypeScript'in tip vokabülerini öğreneceğiz.

Takıldığın yer mi var?

Sor, birlikte çözelim.

community.czay.dev — Türkçe yazılım topluluğumuzda eğitimde takıldığın konuları sorabilir, başka geliştiricilerin deneyimlerinden faydalanabilirsin. Hızlı cevap, doğru yer.