Typescript neden jeneriklerde dairesel referanslara izin vermiyor?

0

Soru

burada, türün tanımında doğrudan kendisine atıfta bulunduğu, ancak genel bir şekilde soyutlandığında tamamen başarısız olduğu örnekler.

type a = { val: a }; // <-- doesn't care about circular references!

type record<T> = { val: T };

type b = record<b>; // <-- doesn't work!

type func<T> = (arg: T) => void;

type c = func<c>; // <-- doesn't work!

type d = (arg: d) => void; // <-- works!?
types typescript
2021-11-23 20:48:45
2

En iyi cevabı

3

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ı

2021-11-23 21:31:48

teşekkürler! bu serin ve yararlı!
radiish
1

Bu senaryoları tek tek inceleyelim.

Senaryo 1

type a = { val: a }; // <-- doesn't care about circular references!

Buna izin verilmesi ilginç. Bu türü tatmin edecek bir örneği nasıl oluşturabileceğinizi anlamıyorum:

const A: a = {
  val: {
    val: {
      // It will always error out at the most inner node.
    }
  }
}

Senaryo 2

type record<T> = { val: T };

Bu dairesel bir referans değildir ve bu şekilde tatmin edilebilir:

const B: record<string> = {
  val: "test"
}

Senaryo 3

type b = record<b>; // <-- doesn't work!

Bunun işe yaramaması bana mantıklı geliyor. Senaryo 1'de olduğu gibi, bu kısıtlamayı karşılayan bir örnek oluşturmanın bir yolu olmayacaktır.

Senaryo 4

type func<T> = (arg: T) => void;

Bu dairesel bir referans değildir ve bu şekilde tatmin edilebilir:

const C: func<string> = (arg: string) => {}

Senaryo 5

type c = func<c>; // <-- doesn't work!

Bunun işe yaramaması bana mantıklı geliyor. Senaryo 1'de olduğu gibi, bu kısıtlamayı karşılayan bir örnek oluşturmanın bir yolu olmayacaktır.

Senaryo 6

type d = (arg: d) => void; // <-- works!?

Aslında bu kısıtlamayı karşılamak için bir işlev yazabilirim, ancak bana ne aldığından emin değilim:

const D: d = (arg) => {}
D(D)
2021-11-23 21:34:19

Diğer dillerde

Bu sayfa diğer dillerde

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................