2016-05-01 20 views
10

Ho il codice seguente:Come creare un tipo di riferimento circolare in TypeScript?

type Document = [number | string | Array<Document>] 

tipografico lamenta con il seguente errore:

test.ts(7,6): error TS2456: Type alias 'Document' circularly references itself. 

refernces Chiaramente circolari non sono ammessi. Tuttavia, ho ancora bisogno di questo tipo di struttura. Quale sarebbe una soluzione per questo?

+0

Apparentemente, i riferimenti di tipo circolare sono consentiti: http: // stackoverflow.it/questions/24444436/circular-type-references-in-typescript – btk

risposta

7

Ecco un modo per farlo:

class Doc { 
    val: number | string | Doc[]; 
} 

let doc1: Doc = { val: 42 }; 
let doc2: Doc = { val: "the answer" }; 
let doc3: Doc = { val: [doc1, doc2] }; 

tipi che si fanno riferimento sono conosciuti come "tipi ricorsivi" e sono discussi in section 3.11.8 della specifica lingua. Il brano che segue spiega il motivo per cui il tentativo di non compila:

Classes and interfaces can reference themselves in their internal structure...

Il tuo esempio originale utilizza né un categoria né un'interfaccia; utilizza un alias di tipo .

+0

Sì, sembra che ci sarà, grazie! – samvv

1

Basandosi su quello che ha detto NPE, tipi non può ricorsivamente puntare a se stessi, si può srotolare questo tipo a qualsiasi livello di profondità che si ritiene sufficiente, ad esempio:

type Document = [number|string|[number|string|[number|string|[number|string]]]] 

Non abbastanza, ma elimina la necessità di un'interfaccia o classe con un valore di proprietà.

+0

In effetti, ci ho pensato, ma sfortunatamente ho bisogno che sia di una profondità infinita. Grazie comunque per la risposta. – samvv

10

Abbiamo già buone risposte, ma penso che possiamo avvicinarsi a quello che si voleva in primo luogo:

Si può provare qualcosa di simile:

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 }]]; 

Rispetto alla risposta di NPE, è non hanno bisogno di oggetti wrapper attorno a stringhe e numeri.

Se si desidera un singolo numero o una stringa di essere un documento valido (che non è quello che hai chiesto, ma ciò che la risposta di NPE implica), si può provare questo:

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 ]; 

Aggiornamento:

L'utilizzo di un'interfaccia con la firma dell'indice anziché una matrice presenta lo svantaggio di perdere le informazioni sul tipo. Typescript non ti consentirà di chiamare metodi array come find, map o forEach. Esempio:

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); 
} 

Questo può essere risolto modificando la definizione di DocumentArray:

interface DocumentArray extends Array<ScalarDocument | DocumentArray> {} 
+0

Interessante ... grazie per aver condiviso questo! – samvv

+0

È inoltre possibile correggere determinati indici per un tipo specifico in questo modo: interfaccia DocumentArray { 0: numero; [indice: numero]: ScalarDocument | DocumentArray; } – rikkertkoppes

3

Il creatore di dattiloscritto spiega come creare tipi ricorsivi qui: https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540

La soluzione per il riferimento circolare è quello di utilizzare extends Array. Nel tuo caso ciò porterebbe a questa soluzione:


type Document = [number | string | DocumentArray] 

interface DocumentArray extends Array<Document> { } 
Problemi correlati