2016-05-01 19 views
10

Mam następujący kod:Jak utworzyć typ odwołania cyklicznego w TypeScript?

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

maszynopis narzeka z powodu następującego błędu:

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

Wyraźnie okrągłe jakieś referencje nie są dozwolone. Jednak nadal potrzebuję tego rodzaju struktury. Jakie byłoby tego obejście?

+0

Najwyraźniej dozwolone są odwołania typu kołowego: http: // stackoverflow.com/questions/24444436/circular-type-references-in-typescript – btk

Odpowiedz

7

Oto jeden ze sposobów, aby to zrobić:

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

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

typów, które odwołują się są znane jako „rekurencyjnych typów” i zostały omówione w section 3.11.8 spec językowej. Poniższy fragment wyjaśnia, dlaczego próba nie kompiluje:

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

Oryginalna przykładzie użyto ani klasy ani interfejs; używa on pseudonimu .

+0

Tak, wygląda na to, że dziękuję! – samvv

1

Opierając się na co NPE powiedział, typy nie mogą rekurencyjnie wskazują na siebie, można rozwinąć tego typu do jakiegokolwiek poziomu głębokości ty za wystarczające, np:

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

Nie dość, ale eliminuje potrzebę interfejs lub klasa z wartością właściwości.

+0

Rzeczywiście, pomyślałem o tym, ale niestety potrzebuję, aby był on nieskończonej głębi. Dzięki za odpowiedź. – samvv

10

Mamy już dobre odpowiedzi, ale myślę, że możemy zbliżyć się do tego, co chciał w pierwszej kolejności:

można spróbować coś takiego:

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

porównaniu do odpowiedzi NPE, w ty nie trzeba otaczać obiektów wokół łańcuchów i liczb.

Jeśli chcesz pojedynczą liczbę lub łańcuch być ważny dokument (który nie jest co pytasz, ale to, co sugeruje odpowiedź NPE), można spróbować to:

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

Aktualizacja:

Używanie interfejsu z podpisem indeksu zamiast tablicy ma tę wadę, że traci informacje o typie. Maszynopis nie pozwala na wywoływanie metod tablic takich jak find, map lub forEach. Przykład:

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

Problem ten można rozwiązać poprzez zmianę definicji DocumentArray:

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

Interesujące ... dziękuję za podzielenie się tym! – samvv

+0

Można również ustalić niektóre indeksy dla określonego typu, jak na przykład: interface DocumentArray { 0: number; [numer indeksu]: ScalarDocument | DocumentArray; } – rikkertkoppes

3

Twórca maszynopis wyjaśnia sposób tworzenia rekurencyjnych typów tutaj: https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540

Rozwiązaniem dla okrągłej odniesienia jest użycie extends Array. W twoim przypadku doprowadziłoby to do rozwiązania tego problemu:


type Document = [number | string | DocumentArray] 

interface DocumentArray extends Array<Document> { } 
Powiązane problemy