TypeScript Interface vs Type: Farklar ve Kullanım Alanları

TypeScript Interface vs Type: Farklar ve Kullanım Alanları
TypeScript'te tip tanımlamanın iki temel yolu vardır: interface ve type alias. Her ikisi de benzer işlevleri yerine getirebilir, ancak aralarında önemli farklar bulunur. Bu yazıda her iki yaklaşımın güçlü yönlerini, sınırlamalarını ve hangi durumlarda hangisinin tercih edilmesi gerektiğini detaylı örneklerle ele alacağız.
Interface Temelleri
Interface, bir nesnenin şeklini (shape) tanımlamak için kullanılır:
// Temel interface tanımı
interface Kullanici {
id: number;
isim: string;
email: string;
yas?: number; // Opsiyonel
readonly kayitTarihi: Date; // Readonly
}
// Interface ile fonksiyon tipi
interface Hesaplama {
(a: number, b: number): number;
}
const topla: Hesaplama = (a, b) => a + b;
const carp: Hesaplama = (a, b) => a * b;
// Interface ile index signature
interface SozlukTipi {
[anahtar: string]: string;
}
const turkceIngilizce: SozlukTipi = {
merhaba: "hello",
dunya: "world"
};
Type Alias Temelleri
Type alias, herhangi bir tipi adlandırmak için kullanılır. Interface'den daha esnek bir yapıya sahiptir:
// Temel type tanımı
type Kullanici = {
id: number;
isim: string;
email: string;
yas?: number;
readonly kayitTarihi: Date;
};
// Primitif tiplere alias
type ID = string | number;
type Email = string;
// Tuple tipi (interface ile yapılamaz)
type Koordinat = [number, number];
type RGBRenk = [number, number, number];
// Union tipi (interface ile yapılamaz)
type Durum = "aktif" | "pasif" | "beklemede";
type Sonuc = Basarili | Hata;
// Mapped type (interface ile yapılamaz)
type ReadonlyKullanici = {
readonly [K in keyof Kullanici]: Kullanici[K];
};
Temel Farklar
1. Declaration Merging
Interface'ler birleştirilebilir (declaration merging), type alias'lar birleştirilemez:
// Interface - Declaration Merging
interface Hayvan {
isim: string;
}
interface Hayvan {
yas: number;
}
// Her iki tanım birleşir
const kedi: Hayvan = {
isim: "Tekir",
yas: 3
};
// Type - Duplicate hata verir
type Bitki = {
isim: string;
};
// type Bitki = { yas: number; }; // HATA! Duplicate identifier 'Bitki'
2. Extends vs Intersection
// Interface - extends ile genişletme
interface Canli {
yasam: boolean;
}
interface Hayvan extends Canli {
isim: string;
tur: string;
}
interface Kedi extends Hayvan {
miyavla(): void;
}
// Type - intersection ile birleştirme
type Canli = {
yasam: boolean;
};
type Hayvan = Canli & {
isim: string;
tur: string;
};
type Kedi = Hayvan & {
miyavla(): void;
};
// Interface, type'ı extend edebilir ve tersi de geçerli
type TemelOzellikler = {
id: number;
olusturmaTarihi: Date;
};
interface Kullanici extends TemelOzellikler {
isim: string;
email: string;
}
3. Union ve Intersection
// Sadece type ile yapılabilecek işlemler
// Union types
type StringVeyaSayi = string | number;
type ApiCevap = BasariliCevap | HataCevap;
// Conditional types
type NonNullable<T> = T extends null | undefined ? never : T;
// Template literal types
type EventAdi = `on${string}`;
// Mapped types
type Opsiyonel<T> = {
[K in keyof T]?: T[K];
};
// Tuple types
type Cift = [string, number];
type UcluVeri = [id: number, isim: string, aktif: boolean];
Performans Farkı
TypeScript derleyicisi, interface'leri dahili olarak daha verimli işler:
// Interface - daha hızlı tip kontrolü
interface KullaniciA {
id: number;
isim: string;
}
interface AdminA extends KullaniciA {
yetki: string[];
}
// Type intersection - biraz daha yavaş
type KullaniciB = {
id: number;
isim: string;
};
type AdminB = KullaniciB & {
yetki: string[];
};
Ne Zaman Hangisini Kullanmalı?
| Senaryo | Tercih | Neden |
|---|---|---|
| Nesne şekli tanımlama | interface | Daha iyi performans ve extends desteği |
| Union/intersection tipler | type | Interface ile yapılamaz |
| Kütüphane API'si | interface | Declaration merging ile genişletilebilir |
| Tuple ve mapped tipler | type | Interface ile yapılamaz |
| Primitif tip alias'ları | type | Interface sadece nesne tipleri için |
| React component props | interface veya type | Takım tercihi / tutarlılık |
Gerçek Dünya Örneği
// E-ticaret uygulaması tip tanımları
// Interface: nesne şekilleri
interface Urun {
id: number;
ad: string;
fiyat: number;
stok: number;
kategori: Kategori;
}
interface Kategori {
id: number;
ad: string;
ustKategori?: Kategori;
}
// Type: union ve utility tipler
type SiparisDurumu = "beklemede" | "hazirlaniyor" | "kargoda" | "teslim_edildi" | "iptal";
type OdemeTipi = "kredi_karti" | "havale" | "kapida_odeme";
type SiparisOzet = Pick<Siparis, "id" | "toplamTutar" | "durum">;
type UrunGuncelleme = Partial<Omit<Urun, "id">>;
// Her ikisini birlikte kullanma
interface Siparis {
id: number;
urunler: Urun[];
toplamTutar: number;
durum: SiparisDurumu;
odemeTipi: OdemeTipi;
musteri: Kullanici;
}
@typescript-eslint/consistent-type-definitions kuralı ile bunu zorunlu hale getirebilirsiniz.
Sonuç
Interface ve type alias, TypeScript'in tip sisteminin iki temel yapı taşıdır. Interface nesne şekillerini tanımlamak için optimize edilmişken, type alias daha geniş bir kullanım alanına sahiptir. Pratikte ikisini birlikte kullanmak en etkili yaklaşımdır: nesne tipleri için interface, union tipler ve utility tipler için type tercih edin. En önemlisi, projenizde tutarlı bir konvansiyon belirleyin ve takımınızla paylaşın.