TypeScript'te interface ve type çoğu durumda birbirinin yerine kullanılabilir: İkisi de bir nesnenin şeklini adlandırır ve derleyici ikisini de yapısal olarak karşılaştırır. Asıl fark şudur: interface sonradan yeniden açılıp yeni alan eklenebilen bir bildirimdir (declaration merging), type ise bir kez tanımlanır ve değiştirilemez. Buna karşılık type yalnızca nesnelere değil union, primitive, tuple ya da fonksiyon tipi gibi her tipe ad verebilir. Handbook'un önerdiği basit kural: type'a özgü bir özelliğe ihtiyaç duyana kadar interface kullanın.
Bu yazıda iki yapıyı yan yana koyuyor, genişletme (extends ve &) farkını, çakışan alanlarda ne olduğunu, declaration merging'in nasıl çalıştığını ve hangi durumda hangisini seçeceğinizi örneklerle anlatıyoruz. Örnekler TypeScript 6.0.3 ile tsc --strict --target es2022 --moduleDetection force seçenekleriyle derlendi; hata kodları ve mesajları bu derleyicinin gerçek çıktısıdır. Temel tipleri henüz görmediyseniz önce TypeScript temel tipler yazısına göz atabilirsiniz.
İkisi de bir nesne şeklini adlandırır

Bir fonksiyon parametresine { x: number; y: number } gibi bir nesne tipini doğrudan yazabilirsiniz. Aynı şekli birden fazla yerde kullanacaksanız ona bir ad vermek istersiniz. Bunun iki yolu vardır ve aşağıdaki iki tanım derleyici açısından aynı işi görür:
type NoktaT = {
x: number;
y: number;
};
interface NoktaI {
x: number;
y: number;
}
function yazdir(n: NoktaI) {
console.log(`(${n.x}, ${n.y})`);
}
const a: NoktaT = { x: 3, y: 7 };
yazdir(a); // (3, 7)
yazdir({ x: 100, y: 100 }); // (100, 100)NoktaT tipindeki bir değeri NoktaI bekleyen fonksiyona hiçbir dönüşüm yapmadan verebildik. Bunun nedeni TypeScript'in yapısal tip sistemi (structural typing) kullanmasıdır: Derleyici tipin adına değil, hangi özelliklere sahip olduğuna bakar. Yani interface ile type arasındaki seçim, değerlerin birbiriyle uyumlu olup olmamasını değiştirmez.
type her tipe ad verebilir, interface yalnızca nesne şekline
Type alias, adından da anlaşılacağı gibi bir tipe takılan addır ve sağ tarafa herhangi bir tip yazılabilir. interface ise yalnızca nesne şekillerini (özellikler, metotlar, çağrı ve kurucu imzaları) tanımlar; bir primitive'i yeniden adlandıramaz ya da union tanımlayamaz:
type Kimlik = number | string; // union
type Koordinat = [number, number]; // tuple
type Karsilastir = (a: string, b: string) => number; // fonksiyon tipi
type Durum = "acik" | "kapali"; // literal union
const k: Kimlik = "a-42";
const c: Koordinat = [41.0, 29.0];
const kiyas: Karsilastir = (a, b) => a.localeCompare(b);
const d: Durum = "acik";
console.log(k, c.length, kiyas("a", "b"), d); // a-42 2 -1 acikBu yüzden union ya da tuple gibi bir yapıya isim vermeniz gerekiyorsa tek seçeneğiniz type'tır. Ayrıca bir interface, union tipindeki bir alias'ı genişletemez; derleyici yalnızca üyeleri önceden bilinen nesne tiplerinin genişletilmesine izin verir:
type Kimlik = number | string;
interface Ozel extends Kimlik {}
// TS2312: An interface can only extend an object type or intersection of object types with statically known members.Önemli bir ayrıntı daha: Type alias yeni ve ayrı bir tip yaratmaz. type TemizMetin = string yazdığınızda TemizMetin beklenen yere sıradan bir string de verilebilir. Bir değerin "temizlenmiş" olduğunu tip düzeyinde garanti etmek için alias tek başına yetmez.
Genişletme: extends ve intersection
Var olan bir tipe yeni alanlar eklemek çok yaygın bir ihtiyaçtır. Interface'te bunu extends ile, type alias'ta ise intersection (kesişim) operatörü & ile yaparsınız. Bir interface birden fazla tipi aynı anda genişletebilir ve nesne şeklindeki bir type alias'ı da genişletebilir:
interface Hayvan {
ad: string;
}
interface Ayi extends Hayvan {
bal: boolean;
}
type HayvanT = { ad: string };
type AyiT = HayvanT & { bal: boolean };
type Renkli = { renk: string };
interface RenkliAyi extends Ayi, Renkli {}
const r: RenkliAyi = { ad: "Boz", bal: true, renk: "kahverengi" };
const t: AyiT = r;
console.log(t.ad, t.bal); // Boz trueSon satırda RenkliAyi değerini AyiT tipine atayabildik, çünkü yine yalnızca yapı karşılaştırılıyor. İki yöntem çoğu zaman aynı sonucu verir; ayrıldıkları yer, aynı adlı bir alan farklı tiplerle karşılaştığında ortaya çıkar.
Çakışan alanlar: extends hata verir, & sessizce never üretir

Handbook'a göre iki yöntem arasındaki temel fark çakışmaların nasıl ele alındığıdır. extends kullandığınızda alt tipteki alan, üst tipteki alanla uyumlu olmak zorundadır; değilse derleyici bildirimin olduğu satırda hata verir:
interface Hayvan {
ad: string;
yas: number;
}
interface Kedi extends Hayvan {
yas: string;
}
// TS2430: Interface 'Kedi' incorrectly extends interface 'Hayvan'.Intersection ise çakışmayı bildirim anında yakalamaz. İki tipi birleştirir ve aynı adlı alanın her iki tipi de aynı anda sağlamasını ister. string ve number olan hiçbir değer olmadığı için alanın tipi never olur ve hatayı ancak değeri kullanmaya çalıştığınızda görürsünüz:
type HayvanT = { ad: string; yas: number };
type KediT = HayvanT & { yas: string };
const kedi: KediT = { ad: "Tekir", yas: "3" };
// TS2322: Type 'string' is not assignable to type 'never'.Bu fark büyük kod tabanlarında önemlidir: extends yanlışlığı tanımın yapıldığı yerde gösterir, intersection ise sorunu kullanım yerine erteler. Intersection'ın ayrıntıları için union ve intersection tipleri yazısına bakabilirsiniz.
Declaration merging: interface yeniden açılabilir
Aynı kapsamda aynı adla iki interface bildirirseniz derleyici bunları tek bir tanımda birleştirir. Buna declaration merging denir. Type alias'ta aynı adı ikinci kez kullanmak ise doğrudan hatadır:
interface Kutu {
en: number;
boy: number;
}
interface Kutu {
olcek: number;
}
const kutu: Kutu = { en: 5, boy: 6, olcek: 10 }; // üç alan da zorunlu
type Paket = { en: number };
type Paket = { boy: number };
// TS2300: Duplicate identifier 'Paket'.Derleyici her iki Paket satırı için de aynı TS2300 hatasını verir. Birleştirmenin de kuralları vardır. Fonksiyon olmayan bir alan iki bildirimde de varsa tipleri aynı olmalıdır:
interface Ayar {
port: number;
}
interface Ayar {
port: string;
}
// TS2717: Subsequent property declarations must have the same type. Property 'port' must be of type 'number', but here has type 'string'.Aynı adlı metotlar ise birbirinin üzerine yazmaz; her biri aynı fonksiyonun bir overload'u olarak eklenir. Handbook'a göre sonra gelen bildirimin overload'ları birleşik listede daha önce yer alır, yani öncelikleri daha yüksektir. Overload kavramını fonksiyon tipleri ve overload yazısında ayrıntılı anlatıyoruz.
Declaration merging pratikte en çok bir kütüphanenin ya da ortamın tiplerine alan eklemek için kullanılır. Örneğin global bir interface'e kendi özelliğinizi eklemek ya da bir modülün dışa açtığı tipi genişletmek (module augmentation) bu mekanizmaya dayanır. Bu kullanımın .d.ts dosyalarıyla ilgili tarafını declaration files yazısında bulabilirsiniz.
Hata mesajları ve derleyici performansı
Handbook iki küçük farka daha dikkat çeker. Birincisi, interface adları hata mesajlarında her zaman kendi adlarıyla görünür (ada göre kullanıldıkları sürece). Type alias adları ise eski sürümlerde bazen yerine eşdeğer anonim tiple gösterilebiliyordu; handbook bunun TypeScript 4.2 öncesi için geçerli olduğunu belirtir. İkincisi, extends ile kurulan interface hiyerarşileri, intersection kullanan type alias'lara göre derleyici için çoğu zaman daha verimli olabilir. Bu bir hız ölçümü değil, TypeScript ekibinin performans rehberindeki genel bir öneridir; küçük projelerde fark hissedilmez.
Karşılaştırma tablosu

| Özellik | interface | type |
|---|---|---|
| Nesne şekli tanımlama | Evet | Evet |
| Union, tuple, primitive alias | Hayır | Evet |
| Genişletme | extends | Intersection (&) |
| Çakışan alan | Bildirimde hata (TS2430) | Alan never olur, hata kullanımda çıkar |
| Aynı adla yeniden bildirme | Birleşir (declaration merging) | Hata (TS2300) |
| Sınıfta implements ile kullanma | Evet | Evet (nesne şeklindeyse) |
| Hata mesajında ad | Her zaman kendi adıyla | Duruma göre |
Hangisini ne zaman kullanmalı?
Handbook'un tavsiyesi açıktır: Çoğu durumda kişisel tercihe göre seçebilirsiniz; bir kural isterseniz type'a özgü bir özellik gerekene kadar interface kullanın. Bu kuralı somut durumlara şöyle çevirebiliriz:
- interface: Nesne ve sınıf şekilleri, bir kütüphanenin dışa açtığı ve kullanıcıların genişletebilmesini istediğiniz tipler,
extendsile kurulan hiyerarşiler. - type: Union ve literal union'lar (literal tipler), tuple'lar, fonksiyon tipleri, mapped ve conditional tipler gibi tip düzeyinde hesaplanan yapılar.
- Tutarlılık: Ekipte hangisini seçerseniz seçin aynı tür tanımlar için aynı yolu izlemek kodu okumayı kolaylaştırır.
Sık yapılan hatalar
- Type alias'ı yeniden açmaya çalışmak: İkinci bir
type Ayar = ...satırı TS2300 verir. Alan eklemek için yeni bir ad ve intersection kullanın ya da tanımı interface'e çevirin. - Intersection'da çakışmayı fark etmemek:
&ile birleştirilen iki tipte aynı ad farklı tiplerle geçiyorsa alanneverolur. Hata, tanımda değil değer atarken çıkar. - Interface ile primitive yeniden adlandırmak:
interface Metin = stringgeçerli bir sözdizimi değildir; bunun içintype Metin = stringyazılır. - Alias'ın ayrı bir tip olduğunu sanmak:
type Eposta = stringile her string'i kabul eden bir ad elde edersiniz, doğrulanmış bir e-posta tipi elde etmezsiniz. - Farkında olmadan birleştirme: Aynı dosyada ya da global kapsamda aynı adlı iki interface sessizce birleşir; beklenmedik zorunlu alanlar görüyorsanız bunu kontrol edin.
Sık Sorulan Sorular
interface mi type mı daha hızlı çalışır?
Çalışma zamanında ikisinin de hiçbir karşılığı yoktur; derleme sonrasında JavaScript çıktısından tamamen silinirler. Handbook'taki performans notu yalnızca derleyicinin tip denetimi işiyle ilgilidir.
Bir sınıf type alias ile tanımlanmış bir şekli implements edebilir mi?
Evet. Sınıflar nesne şeklindeki bir type alias'ı da implements ile uygulayabilir. Union tipindeki bir alias ise uygulanamaz; TypeScript 6.0 bu durumda TS2422 hatasıyla bir sınıfın yalnızca üyeleri önceden bilinen nesne tiplerini uygulayabileceğini söyler.
Declaration merging ne işe yarar?
Var olan bir tanıma dışarıdan alan eklemeyi sağlar. Bir kütüphanenin global ya da modül tiplerine kendi özelliklerinizi eklemek (augmentation) en yaygın kullanımıdır.
Ekipte tek bir kural seçmeli miyiz?
Zorunlu değil, ama faydalıdır. Handbook'un "önce interface" önerisi iyi bir başlangıçtır; union, tuple ya da tip düzeyinde hesaplama gerektiğinde type'a geçersiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: TypeScript öğrenme rehberi · Union ve intersection tipleri · TypeScript temel tipler · Declaration files (.d.ts) · Class ve erişim belirleyiciler · TypeScript ileri seviye yazısı