¿por qué el manuscrito no se permiten referencias circulares en los medicamentos genéricos?

0

Pregunta

aquí los ejemplos en los que el tipo de referencia directamente a sí mismo en su definición, pero cuando extraída a través de un genérico que falle completamente.

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

Mejor respuesta

3

Ver microsoft/Transcripción#41164 para un canónica respuesta a esta pregunta.

Manuscrito no permitir que las referencias circulares en genérico interfaces y genérico de las clases, ya que las interfaces y las instancias de una clase estáticamente conocido propiedad/miembro/método de la teclas y para cualquier circularidad que ocurre en la "caja fuerte" lugares como la propiedad valor des o parámetros de método o tipo de retorno.

interface Interface<T> { val: T }
type X = Interface<X> // okay

class Class<T> { method(arg: T): void { } }
type Y = Class<Y> // okay

Pero para los alias de tipo no existe tal garantía. Tipo de alias puede tener cualquier estructura que cualquier tipo anónimo puede tener, por lo que el potencial de la circularidad no está limitado a recursiva de árbol de objetos:

type Safe<T> = { val: T };
type Unsafe<T> = T | { val: string };

Cuando el compilador crea una instancia de un tipo genérico, se aplaza su evaluación; no tratar de inmediato totalmente calcular el tipo resultante. Todo lo que se ve es de la forma:

type WouldBeSafe = Safe<WouldBeSafe>; 
type WouldBeUnsafe = Unsafe<WouldBeUnsafe>; 

Ambos tienen el mismo aspecto que el compilador... type X = SomeGenericTypeAlias<X>. No puede "ver" que WouldBeSafe estaría bien:

//type WouldBeSafe = { val: WouldBeSafe }; // would be okay

mientras WouldBeUnsafe sería un problema:

//type WouldBeUnsafe = WouldBeUnsafe | { val: string }; // would be error

Puesto que no puede ver la diferencia, y porque al menos algunos de los usos sería ilegal circular, sólo se prohíbe a todos ellos.


Así que, ¿qué puedes hacer? Este es uno de esos casos donde me gustaría sugerir el uso de interface en lugar de type cuando usted puede. Usted puede reescribir su record (tipo de cambio a MyRecord para la convención de nomenclatura razones) como un interface y todo el trabajo:

interface MyRecord<T> { val: T };
type B = MyRecord<B>; // okay

Usted puede incluso reescribir su func (tipo de cambio a Func para la convención de nomenclatura razones de nuevo) como un interface cambiando el tipo de función de expresión de sintaxis en una llamada sintaxis de firma:

interface Func<T> { (arg: T): void }
type C = Func<C>; // okay

Por supuesto, hay situaciones en las que usted no puede hacerlo directamente, tales como la incorporada en el Record tipo de utilidad:

type Darn = Record<string, Darn>; // error

y no se puede reescribir la asignada tipo de Record como un interface. Y, de hecho, no sería seguro para intentar hacer que las teclas de circular, como type NoGood = Record<NoGood, string>. Si sólo quieres hacer Record<string, T> para genéricos Tusted puede reescribir que como un interface:

interface Dictionary<T> extends Record<string, T> { };
type Works = Dictionary<Works>;

Así que hay muy a menudo una manera de utilizar un interface en lugar de type para permitir que usted para expresar "seguro" recursiva tipos.

Patio enlace a código

2021-11-23 21:31:48

gracias! esto es genial y útil!
radiish
1

Vamos a analizar estos escenarios, uno por uno.

Escenario 1

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

Es interesante que este permitido. No veo cómo podría ser capaz de construir una instancia que podría satisfacer este tipo:

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

Escenario 2

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

Esto no es una referencia circular y puede ser satisfecho como este:

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

Escenario 3

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

Tiene sentido para mí que esto no funciona. Al igual que en el Escenario 1, no habría manera de construir una instancia que satisfaga esta restricción.

Escenario 4

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

Esto no es una referencia circular y puede ser satisfecho como este:

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

Escenario 5

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

Tiene sentido para mí que esto no funciona. Al igual que en el Escenario 1, no habría manera de construir una instancia que satisfaga esta restricción.

Escenario 6

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

De hecho, me pueden escribir una función para cumplir con esta restricción, pero no estoy seguro de lo que se está haciendo de mí:

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

En otros idiomas

Esta página está en otros idiomas

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