types - saber - referencia circular c#
¿Cómo crear un tipo de referencia circular en TypeScript? (4)
Aquí hay una forma de hacerlo:
class Doc {
val: number | string | Doc[];
}
let doc1: Doc = { val: 42 };
let doc2: Doc = { val: "the answer" };
let doc3: Doc = { val: [doc1, doc2] };
Los tipos que se refieren a sí mismos se conocen como "tipos recursivos" y se describen en la sección 3.11.8 de la especificación del idioma. El siguiente extracto explica por qué su intento no se compila:
Las clases y las interfaces pueden hacer referencia a sí mismas en su estructura interna ...
Su ejemplo original no usa ni una clase ni una interfaz; utiliza un alias de tipo .
Tengo el siguiente código:
type Document = [number | string | Array<Document>]
TypeScript se queja con el siguiente error:
test.ts(7,6): error TS2456: Type alias ''Document'' circularly references itself.
Claramente las referencias circulares no están permitidas. Sin embargo, todavía necesito este tipo de estructura. ¿Qué sería una solución para esto?
El creador de TypeScript explica cómo crear tipos recursivos aquí: https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540
La solución para la referencia circular es utilizar extends Array
. En su caso esto llevaría a esta solución:
type Document = [number | string | DocumentArray]
interface DocumentArray extends Array<Document> { }
Sobre la base de lo que NPE dijo, los tipos no pueden apuntarse recursivamente a sí mismos, podría desenrollar este tipo a cualquier nivel de profundidad que considere suficiente, por ejemplo:
type Document = [number|string|[number|string|[number|string|[number|string]]]]
No es bonito, pero elimina la necesidad de una interfaz o clase con un valor de propiedad.
Ya tenemos buenas respuestas, pero creo que podemos acercarnos más a lo que querías en primer lugar:
Puedes probar algo como esto:
interface Document {
[index: number]: number | string | Document;
}
// compiles
const doc1: Document = [1, "one", [2, "two", [3, "three"]]];
// fails with "Index signatures are incompatible" which probably is what you want
const doc2: Document = [1, "one", [2, "two", { "three": 3 }]];
Comparado con la respuesta de NPE, no necesita objetos de envoltura alrededor de cadenas y números.
Si desea que un solo número o cadena sea un documento válido (que no es lo que pidió, sino lo que implica la respuesta de NPE), puede intentar esto:
type ScalarDocument = number | string;
interface DocumentArray {
[index: number]: ScalarDocument | DocumentArray;
}
type Document = ScalarDocument | DocumentArray;
const doc1: Document = 1;
const doc2: Document = "one";
const doc3: Document = [ doc1, doc2 ];
Actualizar:
El uso de una interfaz con firma de índice en lugar de una matriz tiene la desventaja de perder información de tipo. Typescript no te permitirá llamar a métodos de matriz como buscar, mapear o forEach. Ejemplo:
type ScalarDocument = number | string;
interface DocumentArray {
[index: number]: ScalarDocument | DocumentArray;
}
type Document = ScalarDocument | DocumentArray;
const doc1: Document = 1;
const doc2: Document = "one";
const doc3: Document = [ doc1, doc2 ];
const doc = Math.random() < 0.5 ? doc1 : (Math.random() < 0.5 ? doc2 : doc3);
if (typeof doc === "number") {
doc - 1;
} else if (typeof doc === "string") {
doc.toUpperCase();
} else {
// fails with "Property ''map'' does not exist on type ''DocumentArray''"
doc.map(d => d);
}
Esto se puede resolver cambiando la definición de DocumentArray:
interface DocumentArray extends Array<ScalarDocument | DocumentArray> {}