2014-01-25 2 views
9

ich eine Klasse haben,Typelite: Warum ist Dictionary <string, object> zu KeyValuePair abgebildet und nicht auf einen oder [index: string]: any

public class Instance : IResource 
{ 
    public Dictionary<string, object> Value { get; set; } 

und es wird abgebildet

interface Instance { 
    Value: System.Collections.Generic.KeyValuePair[]; 

interface KeyValuePair { 
    Key: any; 
    Value: any; 
} 

ich würde

interface Instance { 
    Value: any; 

oder

01 erwartet

Wie kann ich die Generation ändern?

Auch, wie kann ich den Namen Raum in der Generation überspringen?

+0

Ich habe versucht, ".WithConvertor > (t => "any")", aber Das Ergebnis ist "Wert: System.Collections.Generic.any [];" Nicht das, was ich – mattias

Antwort

4

Sammlung Typen (jeder Typ Umsetzung IEnumerable) mit Arrays konvertiert. Dictionary<> implementiert IEnumerable<KeyValuePair<>> und wird daher in ein Array konvertiert. Der Elementtyp wird dann auf seinen vollständig qualifizierten Namen (FQN) erweitert: System.Collections.Generic.KeyValuePair.

Typ Konverter können Sie Zeit den Typ-Namen lassen sich ändern, aber nicht die FQN. Es gilt also nur für lokale Typen. Bei Wörterbüchern können Sie den Elementtyp nicht durch Vererbung ändern.

Sie können entweder einen neuen Wörterbuch Typen erstellen, ohne von Dictionary<> zu vererben. Eine weitere Möglichkeit, um dieses Problem ist, auch Typ Formatter zu verwenden:

ts.WithConvertor<Dictionary<string,object>>(t => { 
    // Embed the real type in $ 
    // "System.Collections.Generic.${ [key: string]: any }$[]" 
    return "${ [key: string]: any }$"; 
}); 
ts.WithFormatter((string memberTypeName, bool isMemberCollection) => { 
    // Extract the content inside $ 
    string[] pieces = memberTypeName.Split('$'); 
    if (pieces.Length == 3) return pieces[1]; 
    // Default behaviour 
    return memberTypeName + (isMemberCollection ? "[]" : ""); 
}); 
+2

Hinweis erwartet, dass 'TypeScriptFluent.WithFormatter()' Überlastungen sind derzeit markiert '[Obsolete]'. – Serguei

8

A quick and dirty Abhilfe ist, einen regulären Ausdruck zu verwenden, um Ausgaben zu ändern:

Mit

<#= Regex.Replace(ts.Generate(TsGeneratorOutput.Properties) 
     , @":\s*System\.Collections\.Generic\.KeyValuePair\<(?<k>[^\,]+),(?<v>[^\,]+)\>\[\];" 
     , m=>": {[key: "+m.Groups["k"].Value+"]: "+m.Groups["v"].Value+"};" 
     , RegexOptions.Multiline) 
#> 

Wandelt ein Feld

myField: System.Collections.Generic.KeyValuePair<string,OtherClass>[]; 

zu

myField: {[key: string]: OtherClass}; 
+0

Funktioniert für mich, danke! – swax

+1

Super! Vergessen Sie nicht das <# @ import namespace = "System.Text.RegularExpressions "#> – BernardV

2

Hier ist eine generalisierte (und aktualisiert) Lösung, die Markus Jarderot die aus der Antwort baut:

static void RegisterDictionaryMemberFormatter(this TsGenerator tsGenerator) 
{ 
    tsGenerator.SetMemberTypeFormatter((tsProperty, memberTypeName) => { 
     var dictionaryInterface = 
      tsProperty.PropertyType.Type.GetInterface(typeof(IDictionary<,>).Name) ?? 
      tsProperty.PropertyType.Type.GetInterface(typeof(IDictionary).Name); 

     if (dictionaryInterface != null) 
     { 
      return tsGenerator.GetFullyQualifiedTypeName(new TsClass(dictionaryInterface)); 
     } 
     else 
     { 
      return tsGenerator.DefaultMemberTypeFormatter(tsProperty, memberTypeName); 
     } 
    }); 
} 

// and if you like the fluent syntax... 
static TypeScriptFluent WithDictionaryMemberFormatter(this TypeScriptFluent typeScriptFluent) 
{ 
    typeScriptFluent.ScriptGenerator.RegisterDictionaryMemberFormatter(); 
    return typeScriptFluent; 
} 

es wie folgt verwendet:

var ts = TypeLite.TypeScript.Definitions().For(typeof(SomeClass).Assembly); 
ts.ScriptGenerator.RegisterDictionaryMemberFormatter(); 

// alternatively with fluent syntax: 

var ts = TypeLite.TypeScript.Definitions() 
    .For(typeof(SomeClass).Assembly) 
    .WithDictionaryMemberFormatter(); 

N. B. Dies korrigiert nur Typ-Signaturen von Eigenschaften (oder Feldern), die Dictionary-Typen haben. Auch Definitionen für IDictionary sind nicht automatisch ausgesendet, dann würden Sie sie manuell hinzufügen:

declare module System.Collections.Generic { 
    interface IDictionary<TKey extends String, TValue> { 
     [key: string]: TValue; 
    } 
} 
declare module System.Collections { 
    interface IDictionary { 
     [key: string]: any; 
    } 
} 
+0

Das ist genial, aber warum würdest du" IDictionary "überhaupt ausgeben, wenn du' {[key: string]: string} 'direkt im Formatierer ausgeben könntest? – caesay

+0

Danke, das ist bei weitem das Beste und sauberste Antwort. – Fl4v

Verwandte Themen