Pozri microsoft/Strojom#41164 pre canonical odpoveď na túto otázku.
Záznam sa povoliť kruhové odkazy v generické rozhranie a generické triedy, od rozhrania a triedy prípadoch majú staticky známe majetok/člen/metóda tlačidlos a preto všetky circularity sa deje v "bezpečí" miesta, ako sú napríklad majetkové hodnotys alebo parametrov metódy alebo návrat typ.
interface Interface<T> { val: T }
type X = Interface<X> // okay
class Class<T> { method(arg: T): void { } }
type Y = Class<Y> // okay
Ale pre všeobecný typ prezývky nie je tam žiadna taká zaručiť. Typ prezývky môže mať štruktúru, že akékoľvek anonymné typu môže mať, tak potenciál circularity nie je fixovaný na rekurzívne strom-ako objekty:
type Safe<T> = { val: T };
type Unsafe<T> = T | { val: string };
Keď kompilátor instantiates všeobecný typ, to odkladá jej vyhodnotenie; to nie je bezprostredne skúste plne vypočítať výsledný typ. Všetko to vidí je formulár:
type WouldBeSafe = Safe<WouldBeSafe>;
type WouldBeUnsafe = Unsafe<WouldBeUnsafe>;
Obe tieto vyzerajú rovnako zostavovateľ... type X = SomeGenericTypeAlias<X>
. To nemôže "vidieť", ktoré WouldBeSafe
bude v poriadku:
//type WouldBeSafe = { val: WouldBeSafe }; // would be okay
zatiaľ čo WouldBeUnsafe
by byť problém:
//type WouldBeUnsafe = WouldBeUnsafe | { val: string }; // would be error
Pretože to nemôže vidieť rozdiel, a keďže aspoň niektoré zvyklosti by byť nelegálne kruhové, to len zakazuje všetky z nich.
Takže, čo môžete urobiť? To je jeden z tých prípadov, kde by som navrhnúť pomocou interface
namiesto type
keď môžete. Môžete prepísať vaše record
typ (zmenou na MyRecord
pre konvencia dôvodov) ako interface
a všetko bude fungovať:
interface MyRecord<T> { val: T };
type B = MyRecord<B>; // okay
Dokonca môžete prepísať vaše func
typ (zmenou na Func
pre konvencia dôvodov znova) ako interface
zmenou funkcie typu prejavu syntax do hovoru podpis syntax:
interface Func<T> { (arg: T): void }
type C = Func<C>; // okay
Samozrejme, sú situácie, kde si nemôže robiť priamo, ako je napríklad vstavaný Record
pomôcka typ:
type Darn = Record<string, Darn>; // error
a nemôžete prepísať mapované typ Record
ako interface
. A naozaj, to by bolo nebezpečné sa snažiť, aby sa tlačidlá kruhová, ako type NoGood = Record<NoGood, string>
. Ak si len chcete urobiť Record<string, T>
pre generické T
si môžete prepísať , že ako interface
:
interface Dictionary<T> extends Record<string, T> { };
type Works = Dictionary<Works>;
Takže tam nie je dosť často, tak na použitie interface
namiesto type
aby ste mohli express "bezpečné" rekurzívne typy.
Ihrisko odkaz na kód