TypeScript Nedir ve Neden Kullanmalıyız?
TypeScript, Microsoft tarafından geliştirilen ve JavaScript'in üzerine statik tip sistemi ekleyen bir programlama dilidir. TypeScript, JavaScript'in bir üst kümesidir; yani her geçerli JavaScript kodu aynı zamanda geçerli TypeScript kodudur. TypeScript derleyicisi (tsc), TypeScript kodunu standart JavaScript'e dönüştürür ve bu sayede her JavaScript ortamında çalışabilir.
TypeScript'in ortaya çıkış nedeni, JavaScript'in dinamik tip yapısının büyük projelerde yol açtığı sorunlardır. Tip hataları, yanlış parametre kullanımı ve tanımsız değişken erişimi gibi hatalar, çalışma zamanında (runtime) ortaya çıkar ve tespit edilmesi zordur. TypeScript, bu hataları derleme zamanında (compile time) yakalar ve geliştiriciye anında geri bildirim sağlar.
TypeScript'in Avantajları
- Erken Hata Tespiti: Tip hataları, kod çalıştırılmadan önce yakalanır
- Gelişmiş IDE Desteği: Otomatik tamamlama, yeniden adlandırma ve kod navigasyonu
- Daha İyi Dokümantasyon: Tipler, kodun nasıl kullanılması gerektiğini belgeler
- Güvenli Refactoring: Tip sistemi sayesinde kod değişiklikleri güvenle yapılabilir
- Ekip İşbirliği: Açık tip tanımları, ekip üyeleri arasında daha iyi iletişim sağlar
- Ölçeklenebilirlik: Büyük kod tabanlarında sürdürülebilirliği artırır
Temel Tipler
TypeScript, JavaScript'in mevcut tiplerine ek olarak zengin bir tip sistemi sunar. Temel tipler şunlardır:
Primitif Tipler
// String
let isim: string = "Ahmet";
// Number (integer ve float ayrımı yoktur)
let yas: number = 30;
let fiyat: number = 29.99;
// Boolean
let aktif: boolean = true;
// Null ve Undefined
let bos: null = null;
let tanimsiz: undefined = undefined;
// BigInt
let buyukSayi: bigint = 9007199254740991n;
// Symbol
let benzersizAnahtar: symbol = Symbol("key");
Dizi (Array) Tipleri
// İki farklı sözdizimi
let sayilar: number[] = [1, 2, 3, 4, 5];
let isimler: Array<string> = ["Ahmet", "Mehmet", "Ayşe"];
// Readonly diziler
let sabitDizi: readonly number[] = [1, 2, 3];
// sabitDizi.push(4); // Hata! Readonly diziye eleman eklenemez
// Tuple (sabit uzunluk ve tip sırası)
let kullanici: [string, number] = ["Ahmet", 30];
let [ad, yasi] = kullanici; // Destructuring ile erişim
Özel Tipler
// Any - herhangi bir tip (tip güvenliğini devre dışı bırakır)
let herhangi: any = "metin";
herhangi = 42; // Hata yok, ama önerilmez
// Unknown - güvenli any alternatifi
let bilinmeyen: unknown = "metin";
// bilinmeyen.toUpperCase(); // Hata! Tip kontrolü gerekli
if (typeof bilinmeyen === "string") {
bilinmeyen.toUpperCase(); // Tip kontrolü sonrası kullanılabilir
}
// Void - değer döndürmeyen fonksiyonlar
function logla(mesaj: string): void {
console.log(mesaj);
}
// Never - asla değer döndürmeyecek fonksiyonlar
function hataFirlat(mesaj: string): never {
throw new Error(mesaj);
}
Interface: Nesne Yapılarını Tanımlama
Interface'ler, nesnelerin şeklini (shape) tanımlamak için kullanılır. TypeScript'in en güçlü özelliklerinden biridir ve kodun okunabilirliğini önemli ölçüde artırır:
interface Kullanici {
id: number;
ad: string;
soyad: string;
email: string;
yas?: number; // İsteğe bağlı alan
readonly olusturmaTarihi: Date; // Sadece okunur alan
}
// Kullanım
const kullanici: Kullanici = {
id: 1,
ad: "Ahmet",
soyad: "Yılmaz",
email: "[email protected]",
olusturmaTarihi: new Date()
};
// kullanici.olusturmaTarihi = new Date(); // Hata! Readonly
Interface Genişletme (Extends)
interface Kisi {
ad: string;
soyad: string;
}
interface Calisan extends Kisi {
departman: string;
maas: number;
}
interface Yonetici extends Calisan {
ekipBuyuklugu: number;
yonettigiDepartmanlar: string[];
}
const yonetici: Yonetici = {
ad: "Mehmet",
soyad: "Kaya",
departman: "Teknoloji",
maas: 50000,
ekipBuyuklugu: 15,
yonettigiDepartmanlar: ["Frontend", "Backend"]
};
Interface vs Type Alias
TypeScript'te nesne yapıları hem interface hem de type alias ile tanımlanabilir. Aralarındaki temel farklar:
| Özellik | Interface | Type Alias |
|---|---|---|
| Genişletme | extends ile | Intersection (&) ile |
| Birleştirme (Merge) | Aynı isimle tekrar tanımlanabilir | Tekrar tanımlanamaz |
| Primitif tipler | Desteklemez | Destekler |
| Union tipler | Desteklemez | Destekler |
| Mapped tipler | Desteklemez | Destekler |
Genel kural olarak, nesne yapıları için interface, diğer tip tanımları için type alias kullanılması önerilir.
Generics: Yeniden Kullanılabilir Tip Yapıları
Generics, tip güvenliğini korurken yeniden kullanılabilir bileşenler oluşturmanızı sağlar. Fonksiyonların, sınıfların ve interface'lerin farklı tiplerle çalışmasına olanak tanır:
// Generic fonksiyon
function ilkElemaniGetir<T>(dizi: T[]): T | undefined {
return dizi[0];
}
const ilkSayi = ilkElemaniGetir([1, 2, 3]); // number | undefined
const ilkMetin = ilkElemaniGetir(["a", "b", "c"]); // string | undefined
// Generic interface
interface ApiYanit<T> {
basarili: boolean;
veri: T;
mesaj: string;
zamanDamgasi: Date;
}
interface Urun {
id: number;
ad: string;
fiyat: number;
}
const urunYaniti: ApiYanit<Urun> = {
basarili: true,
veri: { id: 1, ad: "Laptop", fiyat: 25000 },
mesaj: "Ürün başarıyla getirildi",
zamanDamgasi: new Date()
};
// Generic kısıtlama (Constraints)
interface Uzunlukluk {
length: number;
}
function uzunlukYazdir<T extends Uzunluklug>(deger: T): void {
console.log(`Uzunluk: ${deger.length}`);
}
uzunlukYazdir("merhaba"); // String'in length'i var
uzunlukYazdir([1, 2, 3]); // Dizinin length'i var
// uzunlukYazdir(42); // Hata! Number'ın length'i yok
Enum: Sabit Değer Kümeleri
Enum'lar, adlandırılmış sabit değer kümeleri tanımlamak için kullanılır:
// Sayısal enum
enum Yonler {
Kuzey, // 0
Guney, // 1
Dogu, // 2
Bati // 3
}
// String enum (önerilen)
enum SiparisDurumu {
Beklemede = "BEKLEMEDE",
Onaylandi = "ONAYLANDI",
Kargoda = "KARGODA",
TeslimEdildi = "TESLIM_EDILDI",
IptalEdildi = "IPTAL_EDILDI"
}
function siparisGuncelle(durum: SiparisDurumu): void {
console.log(`Sipariş durumu: ${durum}`);
}
siparisGuncelle(SiparisDurumu.Kargoda);
// Const enum (derleme zamanında inline edilir)
const enum Renk {
Kirmizi = "#FF0000",
Yesil = "#00FF00",
Mavi = "#0000FF"
}
String enum'lar, sayısal enum'lara göre daha okunabilir ve hata ayıklamada daha kullanışlıdır. Const enum'lar ise derleme sonucunda daha küçük JavaScript kodu üretir.
Type Guards: Tip Daraltma
Type guard'lar, bir değişkenin tipini çalışma zamanında kontrol ederek TypeScript derleyicisine doğru tipi bildirmenizi sağlar:
// typeof ile tip kontrolü
function islemYap(deger: string | number): string {
if (typeof deger === "string") {
return deger.toUpperCase(); // string olarak tanınır
}
return deger.toFixed(2); // number olarak tanınır
}
// instanceof ile sınıf kontrolü
class Kopek {
havla() { return "Hav!"; }
}
class Kedi {
miyavla() { return "Miyav!"; }
}
function hayvanSesi(hayvan: Kopek | Kedi): string {
if (hayvan instanceof Kopek) {
return hayvan.havla();
}
return hayvan.miyavla();
}
// Discriminated Union ile tip daraltma
interface Daire {
tur: "daire";
yaricap: number;
}
interface Dikdortgen {
tur: "dikdortgen";
genislik: number;
yukseklik: number;
}
type Sekil = Daire | Dikdortgen;
function alanHesapla(sekil: Sekil): number {
switch (sekil.tur) {
case "daire":
return Math.PI * sekil.yaricap ** 2;
case "dikdortgen":
return sekil.genislik * sekil.yukseklik;
}
}
// Custom type guard fonksiyonu
function isDaire(sekil: Sekil): sekil is Daire {
return sekil.tur === "daire";
}
Utility Types: Yerleşik Yardımcı Tipler
TypeScript, yaygın tip dönüşümleri için hazır utility type'lar sunar:
interface Kullanici {
id: number;
ad: string;
email: string;
sifre: string;
aktif: boolean;
}
// Partial - tüm alanları isteğe bağlı yapar
type KullaniciGuncelleme = Partial<Kullanici>;
// Required - tüm alanları zorunlu yapar
type ZorunluKullanici = Required<Kullanici>;
// Pick - belirli alanları seçer
type KullaniciOzet = Pick<Kullanici, "id" | "ad" | "email">;
// Omit - belirli alanları hariç tutar
type KullaniciPublic = Omit<Kullanici, "sifre">;
// Record - anahtar-değer eşlemesi
type KullaniciRolleri = Record<string, string[]>;
const roller: KullaniciRolleri = {
admin: ["okuma", "yazma", "silme"],
editor: ["okuma", "yazma"],
izleyici: ["okuma"]
};
// Readonly - tüm alanları salt okunur yapar
type SabitKullanici = Readonly<Kullanici>;
// ReturnType - fonksiyon dönüş tipini çıkarır
function kullaniciOlustur() {
return { id: 1, ad: "Ahmet", aktif: true };
}
type KullaniciTipi = ReturnType<typeof kullaniciOlustur>;
// Exclude ve Extract
type Durum = "aktif" | "pasif" | "askida" | "silindi";
type AktifDurumlar = Exclude<Durum, "silindi">; // "aktif" | "pasif" | "askida"
type SilinmisDurum = Extract<Durum, "silindi">; // "silindi"
Dekoratörler (Decorators)
Dekoratörler, sınıflara ve üyelerine meta veri eklemek veya davranışlarını değiştirmek için kullanılır. Angular framework'ünde yaygın olarak kullanılırlar. TypeScript 5.0 ile birlikte TC39 Stage 3 dekoratör standardı desteklenmektedir:
// Sınıf dekoratörü
function Logger(constructor: Function) {
console.log(`${constructor.name} sınıfı oluşturuldu`);
}
@Logger
class KullaniciServisi {
// ...
}
// Method dekoratörü
function ZamanOlc(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
const baslangic = performance.now();
const sonuc = originalMethod.apply(this, args);
const bitis = performance.now();
console.log(`${propertyKey} metodu ${bitis - baslangic}ms sürdü`);
return sonuc;
};
}
class VeriServisi {
@ZamanOlc
buyukVeriIsle(veri: any[]) {
// İşlem...
}
}
TypeScript Yapılandırması: tsconfig.json
tsconfig.json dosyası, TypeScript derleyicisinin davranışını yapılandırır. Önemli yapılandırma seçenekleri:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"sourceMap": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
En önemli yapılandırma seçeneği strict: true seçeneğidir. Bu seçenek, strictNullChecks, noImplicitAny, strictFunctionTypes gibi tüm katı tip kontrol kurallarını etkinleştirir. Yeni projelerde her zaman strict modda başlamak önerilir.
JavaScript'ten TypeScript'e Geçiş
Mevcut bir JavaScript projesini TypeScript'e geçirmek kademeli olarak yapılmalıdır:
Adım Adım Geçiş Stratejisi
- tsconfig.json oluşturun:
allowJs: trueile başlayın, böylece JS ve TS dosyaları bir arada çalışabilir - .js dosyalarını .ts olarak yeniden adlandırın: Öncelikli dosyalardan başlayarak kademeli dönüştürün
- Strict modunu kademeli etkinleştirin: Önce
strict: falseile başlayın, sonra kuralları tek tek açın - Any tiplerini kaldırın: Başlangıçta any kullanmak kabul edilebilir, ancak zamanla doğru tiplere dönüştürün
- Üçüncü parti tipleri ekleyin: @types/* paketlerini yükleyin
Geçiş İpuçları
- Tüm projeyi tek seferde dönüştürmeye çalışmayın
- En çok kullanılan ve en kritik modüllerden başlayın
- Mevcut testlerin geçtiğinden emin olun
- Ekip içinde TypeScript eğitimi sağlayın
- ESLint ve TypeScript ESLint eklentilerini yapılandırın
En İyi Uygulamalar
- any kullanımından kaçının: unknown veya doğru tip tanımlarını tercih edin
- Strict modda çalışın: Tip güvenliğini maksimize eder
- Type assertion (as) yerine type guard kullanın: Çalışma zamanı güvenliği sağlar
- Interface'leri tercih edin: Nesne tipleri için interface, diğerleri için type alias
- Enum yerine const object veya union type düşünün: Daha hafif JavaScript çıktısı
- Return tiplerini açıkça belirtin: Özellikle public API'lerde
- Index signature yerine Record veya Map kullanın: Daha güvenli tip kontrolü
- Null kontrollerini ihmal etmeyin: strictNullChecks her zaman açık olsun
TypeScript, JavaScript'e tip güvenliği eklemenin ötesinde, kodunuzun tasarımını düşünmenizi ve daha iyi mimari kararlar almanızı sağlayan bir araçtır. İyi bir tip tasarımı, iyi bir yazılım tasarımının yansımasıdır.
TypeScript Ekosistemi
TypeScript ekosistemi hızla büyümektedir ve hemen her popüler JavaScript kütüphanesi TypeScript desteği sunmaktadır:
- Zod: Runtime tip doğrulama ve schema tanımlama
- tRPC: End-to-end tip güvenli API'ler
- Prisma: Tip güvenli veritabanı erişimi
- ts-pattern: Pattern matching kütüphanesi
- Effect: Fonksiyonel programlama ve hata yönetimi
Sonuç
TypeScript, modern web geliştirmenin vazgeçilmez bir aracı haline gelmiştir. Statik tip sistemi sayesinde hataları erken yakalar, IDE deneyimini zenginleştirir ve büyük kod tabanlarında sürdürülebilirliği artırır. Bu rehberde ele aldığımız temel tipler, interface, generic, enum, type guard, utility type ve dekoratörler, TypeScript'in sunduğu güçlü araçların yalnızca bir kısmıdır. TypeScript'i öğrenmek, JavaScript bilginizi güçlendiren ve sizi daha iyi bir geliştirici yapan bir yatırımdır. Küçük projelerden başlayarak tip sistemiyle tanışın ve kademeli olarak ileri düzey özellikleri keşfedin.