Mert Özen Her Satırda Daha İleri
Frontend TypeScript Temel — #02

TypeScript Kurulumu: Kodu Çalıştırmak ile Tip Denetimi Aynı Şey Değil

Mert Özen 3 Kas 2026 7 dk 1 görüntülenme
TypeScript Kurulumu: Kodu Çalıştırmak ile Tip Denetimi Aynı Şey Değil

TypeScript Playground, npm ile kurulum, tsc --init, npx tsc --noEmit ve Node 26 ile node file.ts: kodu çalıştırmanın neden tip denetimi anlamına gelmediğini ve ilk hata mesajını okumayı görüyoruz.

Sürüm notu: Bu yazıdaki kodlar TypeScript 7.0 ve Node 26 içindir.

Önce Tahmin Et

Bir önceki yazıda TypeScript'in hatalı bir argümanı kod çalışmadan yakaladığını gördük. Şimdi aynı fikri kendi bilgisayarına taşıyacağız. Elinde hello.ts adında şöyle bir dosya olsun:

function greet(name: string): string {
  return `Hello, ${name}!`;
}

console.log(greet(42));

greet bir string bekliyor, biz ona bir sayı veriyoruz. Bu dosyayı terminalde node hello.ts ile çalıştırırsan ne olur? Node bir TypeScript hatası mı gösterir, yoksa konsola bir şey yazıp devam mı eder? Tahminini aklında tut; cevabı kodu çalıştırdığımız bölümde vereceğiz.

En Hızlı Yol: TypeScript Playground

Hiçbir şey kurmadan başlamak istiyorsan typescriptlang.org/play adresi yeterli. Sol tarafa kodunu yazarsın, hatalı satırlar anında kırmızıyla çizilir. Sağ taraftaki panelde birkaç sekme var: ".JS" sekmesi kodunun tipleri silinmiş JavaScript hâlini, ".D.TS" sekmesi ise kodundan çıkan declaration dosyasını gösterir. Declaration dosyası, yalnızca tiplerden oluşan bir özet gibidir; ne olduğunu Orta seride ayrıntılı göreceğiz. "Errors" sekmesi hataları listeler, "Run" düğmesi kodu tarayıcıda çalıştırır ve console.log çıktısını "Logs" sekmesinde gösterir.

Playground'un en sevdiğim yanı paylaşılabilir olması. Adres çubuğundaki link, yazdığın kodu da içinde taşır. Bir hatayı bir arkadaşına sormak istediğinde ekran görüntüsü yerine bu linki gönderirsin; o da aynı kodu, aynı ayarlarla açar.

Bir not: Playground'un üst kısmındaki sürüm menüsünde şu an en yeni kararlı sürüm 6.0 serisidir, çünkü Playground hâlâ JavaScript ile yazılmış derleyiciyi kullanıyor. Temel konularda 6.0 ile 7.0 aynı davranır ve varsayılan ayarlar da aynıdır, bu yüzden bu serideki örnekler iki tarafta da aynı sonucu verir.

Projeye TypeScript Kurmak

Gerçek projeler kendi bilgisayarında yaşar. Boş bir klasör açalım ve TypeScript'i bu projenin bağımlılığı olarak kuralım:

mkdir ts-sandbox
cd ts-sandbox
npm init -y
npm i -D typescript
npx tsc -v

Son komut Version 7.0.2 gibi bir satır yazdırır. npm i -D typescript artık Go ile yazılmış yeni derleyiciyi kurar; komutun adı yine tsc.

Neden global kurulum (npm i -g) değil? Çünkü TypeScript'in her sürümü biraz farklı davranır. Sürümü package.json içine yazdığında projeyi klonlayan herkes aynı derleyiciyle çalışır. npx tsc da projenin node_modules klasöründeki derleyiciyi bulup çalıştırır. Eski kaynaklarda hâlâ global kurulum önerisi görebilirsin; bugün bunu yapmanın bir faydası yok.

tsc --init ile Sade Bir tsconfig

Derleyiciye hangi kurallarla çalışacağını tsconfig.json dosyası söyler. Elle yazmana gerek yok, şu komut senin için üretir:

npx tsc --init

Ortaya çıkan dosyada bol miktarda açıklama satırı var. Yorumları çıkardığımızda kalan ayarlar şunlar:

{
  "compilerOptions": {
    "module": "nodenext",
    "target": "esnext",
    "types": [],
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "strict": true,
    "jsx": "react-jsx",
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "noUncheckedSideEffectImports": true,
    "moduleDetection": "force",
    "skipLibCheck": true
  }
}

Hepsini şimdi ezberlemen gerekmiyor. Şimdilik üç şeyi bil. strict: true en önemli satır; TypeScript'in sıkı denetim kurallarını bir arada açar ve bu seri baştan sona bu modda ilerler. module ve target kodun hangi JavaScript sürümüne ve module sistemine göre yorumlanacağını belirler. noUncheckedIndexedAccess ve exactOptionalPropertyTypes ise strict'in de ötesine geçen iki ek kural; ikisine de array ve object yazılarında değineceğiz. Bu dosyanın bütün satırlarını tsconfig'e ayırdığımız yazıda tek tek açacağız.

Tip Denetimi: npx tsc --noEmit

Şimdi hello.ts dosyasını klasöre koy ve derleyiciyi çalıştır:

npx tsc --noEmit

--noEmit, "sadece denetle, dosya üretme" demek. Derleyici tsconfig.json dosyasını bulur, projedeki .ts dosyalarını okur ve şunu raporlar:

hello.ts:5:19 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

5 console.log(greet(42));
                    ~~


Found 1 error in hello.ts:5

Hata yoksa komut hiçbir şey yazdırmaz ve sessizce biter. TypeScript dünyasında sessizlik iyi haberdir. Komut ayrıca hata olduğunda sıfırdan farklı bir çıkış koduyla biter; bu sayede CI gibi otomatik süreçlerde tip hatası olan kodun ilerlemesini durdurabilirsin.

Çalıştırmak: node hello.ts

Node 26, .ts dosyalarını doğrudan çalıştırabilir. Arkasındaki teknik "type stripping": Node dosyayı okur, type annotation'ları siler ve geriye kalan JavaScript'i çalıştırır. Ek bir paket ya da ayar gerekmez:

node hello.ts

İşte tahminin cevabı: konsolda Hello, 42! yazar. Node hiçbir hata göstermez, çünkü tipleri denetlemez; onları sadece siler. Annotation'lar gidince geriye greet(42) çağrısı kalır ve JavaScript bir sayıyı template literal içine koymaktan hiç çekinmez.

Bu yazının asıl dersi bu: çalışıyor olması, tiplerin doğru olduğu anlamına gelmez. Çalıştırmak ile tip denetimi iki ayrı iştir ve iki ayrı araç yapar. node hello.ts kodu çalıştırır, npx tsc --noEmit tipleri denetler. Gerçek bir projede ikisini de kullanırsın. Bu ayrımın bir faydası da var: tip denetimi tüm projeyi okuduğu için zaman alabilir, çalıştırma ise anında başlar.

Node'un tipleri sadece silebilmesinin bir sonucu daha var. TypeScript'in, silinince geride JavaScript bırakmayan birkaç özel syntax'ı var; enum bunun en bilinen örneği. Node bunları silemediği için hata verir. Bu serideki örnekleri bu yüzden sadece silinebilir syntax'la yazıyoruz; istisnaları kendi yazılarında, farkını açıklayarak göstereceğiz. Node tarafının ayrıntıları ise Node serisinin konusu.

İlk Hata Mesajını Okumak

Yukarıdaki çıktıya geri dönelim, çünkü TypeScript ile geçireceğin zamanın önemli bir kısmı bu mesajları okumakla geçecek. hello.ts:5:19 dosya adı, satır ve sütundur: 5. satırın 19. karakteri, yani 42'nin başladığı yer. Ardından gelen TS2345 hatanın kodudur. Her hata türünün sabit bir numarası vardır; bu kodu arattığında aynı hatayı yaşamış yüzlerce kişinin sorusunu bulursun.

Sonra mesajın kendisi gelir: "Argument of type 'number' is not assignable to parameter of type 'string'." Bu kalıbı çok göreceksin. Önce verdiğin şeyin type'ını (number), sonra beklenen type'ı (string) söyler. Bir alt satırda hatalı satırın kendisi, altındaki ~~ işaretleriyle sorunlu kısım gösterilir. En sonda da toplam hata sayısı yazar.

Çıktıyı bir dosyaya yönlendirdiğinde ya da CI'da çalıştırdığında renkler ve kod parçası kaybolur, mesaj tek satıra iner: hello.ts(5,19): error TS2345: …. Biçim farklı ama bilgi aynı.

Editör Desteği

Pratikte hataların çoğunu terminalde değil, editörde görürsün. VS Code TypeScript desteğiyle birlikte gelir; ek bir eklenti kurmadan .ts dosyanı açtığında hatalı satırın altı kırmızıyla çizilir. Çizginin üzerine geldiğinde terminalde gördüğün mesajın aynısını görürsün. Bir değişkenin üzerine geldiğinde ise TypeScript'in o değişken için hangi type'ı bulduğunu gösterir; bir sonraki yazıda bu özelliği çok kullanacağız.

Editör tip denetimini yazdığın anda yapar ama yalnızca açık olan dosyalara odaklanır; kendi içinde taşıdığı TypeScript sürümü de projedekinden farklı olabilir. Bu yüzden son sözü her zaman npx tsc --noEmit söyler. Editör, yazarken yanında duran bir yardımcı; tsc ise kapıdaki son kontrol.

Sık Düşülen Tuzaklar

Birinci tuzak, tek bir dosyayı denetlemek isterken çıkar. Klasörde tsconfig.json varken npx tsc hello.ts yazarsan şu hatayı alırsın:

error TS5112: tsconfig.json is present but will not be loaded if files are specified on commandline. Use '--ignoreConfig' to skip this error.

Eskiden bu komut tsconfig'i sessizce yok sayıp dosyayı varsayılan ayarlarla derliyordu ve insanlar neden farklı hatalar gördüğünü anlamıyordu. Artık açıkça hata veriyor. Projenin tamamını denetlemek istiyorsan dosya adı vermeden npx tsc --noEmit yaz. Gerçekten tek bir dosyayı tsconfig'den bağımsız denetlemek istiyorsan bunu açıkça söyle:

npx tsc --noEmit --ignoreConfig hello.ts

İkinci tuzak, --noEmit'i unutmak. Sadece npx tsc yazarsan derleyici denetimin yanında dosya da üretir; bizim tsconfig ile hello.ts'in yanında hello.js, hello.d.ts ve iki tane .map dosyası belirir. Üstelik hata olsa bile bu dosyaları üretir. Kodu Node ile doğrudan çalıştırdığımız sürece bu çıktılara ihtiyacımız yok.

Üçüncüsü, en tehlikelisi: "Node çalıştırdı, demek ki doğru" diye düşünmek. Az önce gördüğün gibi Node tip hatası olan kodu da çalıştırır. Bir dosyayı çalıştırmadan önce ya editördeki kırmızı çizgilere bak ya da npx tsc --noEmit çalıştır.

Küçük Bir Deneme

★☆☆ Bu yazıdaki adımları kendi bilgisayarında uygula: klasörü oluştur, TypeScript'i kur, tsc --init çalıştır ve hello.ts'i hem npx tsc --noEmit hem de node hello.ts ile dene. İki komutun çıktısını yan yana koy.

★★☆ Tahmin et, sonra dene: greet(42) yerine greet("Ada", "Grace") yazarsan npx tsc --noEmit ne der, node hello.ts ne yazdırır? Hata kodunu ve sütun numarasını not et.

★★☆ package.json içindeki scripts bölümüne "check": "tsc --noEmit" satırını ekle ve npm run check ile çalıştır. Hata varken ve yokken komutun nasıl bittiğine bak.

★★★ Aynı hello.ts'i Playground'a yapıştır, linki kopyala ve yeni bir sekmede aç. Ardından ".JS" sekmesindeki çıktıyı, Node'un çalıştırdığı kodla karşılaştır: tipler silindiğinde geriye ne kalıyor?

Ortam hazır. Artık hem çalıştırabiliyor hem de denetleyebiliyoruz. Bir sonraki yazıda editördeki o "üzerine gel, type'ı gör" özelliğini sonuna kadar kullanacağız: TypeScript bir değişkenin type'ını nasıl kendisi çıkarıyor, biz ne zaman annotation yazmalıyız ve ne zaman yazmamalıyız.