Değişkenlik, bir bileşik türün alt tiplemesinin, parçalarının alt tiplemesiyle nasıl ilişkili olduğunu açıklar — yani Container<Sub> ne zaman Container<Super> atanabilir?
Dog öğesinin Animal öğesinin bir alt türü olduğunu varsayalım.
Değişkenlik, bir bileşik türün alt tiplemesinin, parçalarının alt tiplemesiyle nasıl ilişkili olduğunu açıklar — yani Container<Sub> ne zaman Container<Super> atanabilir?
Dog öğesinin Animal öğesinin bir alt türü olduğunu varsayalım.
let dogs: Dog[] = [];
let animals: Animal[] = dogs; // ✅ Dog[] is assignable to Animal[]
Dönüş türleri ve diziler kovaryanttır: Dog ⊆ Animal ise, Dog[] ⊆ Animal[]. Dog döndüren bir işlev, Animal döndüren birin beklendiği yerde kullanılabilir.
type Handler<T> = (arg: T) => void;
let animalHandler: Handler<Animal> = (a) => {};
let dogHandler: Handler<Dog> = animalHandler; // ✅ (with strictFunctionTypes)
// a handler that accepts ANY Animal can safely handle a Dog
İşlev parametreleri kontravaryant: Handler<Animal> Handler<Dog> atanabilir, bu eleman ilişkisinin tersidir. Bu sağlamdır — tüm hayvanları işleyen bir şey kesinlikle köpekleri işler.
// Method parameters in TS are bivariant by default (a known unsound convenience)
interface Comparer<T> { compare(a: T): void; }
TypeScript, tek başına işlev türlerini strictFunctionTypes altında yalnızca kontravaryant olarak kontrol eder; metot parametreleri ergonomi için kasıtlı olarak bivaryant olup, bu teknik olarak sağlam değildir.
Değişkenlik, belirli atamaların neden izin verildiğini veya reddedildiğini açıklar — neden Dog[] Animal[] düşer, ancak (d: Dog) => void geri araması her zaman (a: Animal) => void yerine geçemez.
Bunu anlamak, genel API ler tasarlamanıza (ör. salt okunur vs yazma konumları) ve işlevleri ve genel türleri içeren kafa karıştırıcı "atanamazlık" hatalarını çözmenize yardımcı olur.
Junior'dan Senior'a detaylı cevaplarla bir BT mülakat soruları kütüphanesi.
Bağış Yap