Bu sorunun kurallı bir cevabı için microsoft/TypeScript#41164'e bakın.
TypeScript, arabirimler ve sınıf örnekleri statik olarak bilinen özellik/üye/yöntem anahtarı s'ye sahip olduğundan ve bu nedenle özellik değeri s veya yöntem parametreleri veya dönüş türü gibi "güvenli" yerlerde herhangi bir döngüsellik gerçekleştiğinden, genel arabirimlerde ve genel sınıflarda döngüsel başvurulara izin verir.
interface Interface<T> { val: T }
type X = Interface<X> // okay
class Class<T> { method(arg: T): void { } }
type Y = Class<Y> // okay
Ancak genel tür takma adları için böyle bir garanti yoktur. Tür takma adları, herhangi bir anonim türün sahip olabileceği herhangi bir yapıya sahip olabilir, bu nedenle potansiyel çevresellik özyinelemeli ağaç benzeri nesnelerle sınırlandırılmaz:
type Safe<T> = { val: T };
type Unsafe<T> = T | { val: string };
Derleyici genel bir türün örneğini oluşturduğunda, değerlendirmesini erteler; hemen sonuç türünü tam olarak hesaplamaya çalışmaz. Tek gördüğü form:
type WouldBeSafe = Safe<WouldBeSafe>;
type WouldBeUnsafe = Unsafe<WouldBeUnsafe>;
Bunların her ikisi de derleyiciye aynı görünüyor... type X = SomeGenericTypeAlias<X>
. Bunu "göremez" WouldBeSafe
olur Tamam:
//type WouldBeSafe = { val: WouldBeSafe }; // would be okay
karşın WouldBeUnsafe
bu bir sorun olurdu:
//type WouldBeUnsafe = WouldBeUnsafe | { val: string }; // would be error
Farkı göremediğinden ve en azından bazı kullanımlar yasadışı olarak dairesel olacağından, hepsini yasaklar.
Peki, ne yapabilirsin? Bu, kullanmanızı önereceğim durumlardan biri interface
yerine type
yapabildiğin zaman. Sen kendi yeniden yazabilirsiniz record
tür (olarak değiştirme MyRecord
adlandırma kuralı nedenleriyle) olarak interface
ve her şey işe yarayacak:
interface MyRecord<T> { val: T };
type B = MyRecord<B>; // okay
Hatta yeniden yazabilirsiniz func
tür (olarak değiştirme Func
yeniden adlandırma kuralı nedenleriyle) olarak interface
işlev türü ifade sözdizimini çağrı imzası sözdizimine değiştirerek:
interface Func<T> { (arg: T): void }
type C = Func<C>; // okay
Tabii ki, bunu doğrudan yapamayacağınız durumlar vardır, örneğin yerleşikRecord
yardımcı program türü:
type Darn = Record<string, Darn>; // error
ve eşlenen türü yeniden yazamazsınız Record
bir olarak interface
. Ve gerçekten de, anahtarları dairesel hale getirmeye çalışmak güvensiz olurdu, örneğin type NoGood = Record<NoGood, string>
. Eğer sadece yapmak istiyorsan Record<string, T>
jenerik için T
, bunu bir olarak yeniden yazabilirsiniz interface
:
interface Dictionary<T> extends Record<string, T> { };
type Works = Dictionary<Works>;
Bu yüzden sık sık kullanmanın bir yolu var interface
yerine type
"güvenli" özyinelemeli türleri ifade etmenize izin vermek için.
Oyun alanı koduna bağlantı