Come riutilizzare le definizioni di classi C # esistenti nei progetti TypeScript


121

Inizierò solo l'uso TypeScriptnel mio progetto client HTML che appartiene a un progetto MVC con un modello di dominio del framework di entità già presente. Voglio che i miei due progetti (lato client e lato server) siano completamente separati in quanto due team lavoreranno su questo ... JSON e REST vengono utilizzati per comunicare oggetti avanti e indietro.

Ovviamente, i miei domainoggetti sul lato client dovrebbero corrispondere agli oggetti sul lato server. In passato, normalmente l'ho fatto manualmente. C'è un modo per riutilizzare le mie definizioni di classe C # (specialmente delle POJOclassi nel mio modello di dominio) per creare le classi corrispondenti in TypeScript "?


No, sono lingue completamente diverse.
Hans Passant

6
Sì, intendevo POCO. So che sono linguaggi totalmente diversi ... ma sarebbe bello evitare in qualche modo di digitare di nuovo tutto questo ... Penso che per il momento copierò e incollerò il mio codice c # .. e rifatterò qualsiasi cosa finché non verrà compilato in TypeScript ... in questo modo sono sicuro di non aver digitato un attributo sbagliato .. e aiutami a non doverlo ricordare. Ma questo chiaramente non suona affatto carino.
pabloelustondo

1
Mi interessa anche l'altra direzione: dalle classi del modello Typescript alle classi del modello C #, deserializzabili bidirezionalmente tramite JSON.
Jason Kleban

Ho cercato lo stesso e mi sono appena imbattuto in questo plugin Gulp anche se non so quanto supporto ci sia per esso
Luke T O'Brien

Risposte:


54

Attualmente non esiste nulla che associ C # a TypeScript. Se hai molti POCO o pensi che potrebbero cambiare spesso, potresti creare un convertitore, qualcosa di semplice sulla falsariga di ...

public class MyPoco {
    public string Name { get; set; }
}

Per

export class MyPoco {
    public Name: string;
}

C'è anche una discussione su Codeplex sulla generazione automatica da C # .

Solo per mantenere le cose aggiornate, TypeLite può generare interfacce TypeScript da C #:

http://type.litesolutions.net/


Sì, qualcosa del genere è quello che stavo pensando di fare manualmente .. bene. Non sono sicuro di avere tempo per scrivere un convertitore adesso .. ma sì, questa sarebbe l'idea. Grazie. Potrebbe essere che Microsoft lo stia facendo proprio ora mentre parliamo.
pabloelustondo

Puoi farlo in uno dei due modi ... Genera file .ts con l'aiuto di EnvDTE Automation o usando Mef Directory Catalog e Reflection / Introspection. Preferisco il secondo in quanto non dipende dalla visuale.
Arek Bal

1
Stavo iniziando a usare dart e mi sono imbattuto nello stesso problema di come condividere i tipi tra c # e javascript. Speravo che questo problema sarebbe stato risolto da Typescript, ma sembra che la risposta non sia ancora. Sono stato anche un po 'viziato dal compilatore saltarelle che ha compilato c # in javascript piuttosto bene saltarelle-compiler.com
BraveNewMath

2
@DanielHarvey Gli enum sono generati correttamente da TypeLite, probabilmente risolti dal tuo commento.
pauloya

1
TypeScriptPaste convertirà C # inTypescript. Devi avere il compilatore Roslyn, che significa Visual Studio 2015, ma funziona davvero bene. Non è al 100% e ho dovuto smorzare un po 'di codice - convertendo foreach in cicli for, scrivendo la mia classe List <T>, per esempio, e devi strutturare il tuo codice in modo che sia `` puro' 'con solo strutture di dati interne per lavorare con, ma era un piccolo prezzo da pagare per poter modificare e testare il codice in VS e poi "compilarlo" in Javascript tramite TypeScript.
John Mott

36

Web Essentials consente di compilare file C # in file TypeScript .d.tsal salvataggio. Quindi puoi fare riferimento alle definizioni dai tuoi .tsfile.

inserisci qui la descrizione dell'immagine


Stai forse confondendo i file .ts e c #? non riesco a trovare questa opzione
Flores

1
Ma dopo qualche ricerca ho trovato quello che intendi .. in realtà abbastanza utile.
Flores

2
In realtà non lo è, sono abbastanza sicuro che l'operazione non "compili" nulla, genera codice. Questo mi ha confuso, ma non è corretto al 99%, te lo do ;-)
Flores

1
Sarebbe stato più utile se potessimo configurare il suo spazio dei nomi e alcune personalizzazioni.
Farshid Saberi

5
Ora devi installare manualmente 'TypeScript Definition Generator' per usarlo - vedi qui
Taran

24

TypeLite e T4TS sopra sembravano buoni, ne ho appena scelto uno, TypeLite, l'ho biforcato per ottenere supporto per

  • ValueTypes ,
  • nullables
  • camelCasing (il documento radice di TypeScript usa i cammelli, e questo va troppo bene insieme a C #)
  • campi pubblici (adoro i POCO puliti e leggibili, facilita anche il compilatore C #)
  • disabilita la generazione del modulo

Poi avevo bisogno di interfacce C # e ho pensato che fosse ora di creare qualcosa di mio e ho scritto un semplice script T4 che fa proprio quello che mi serve. Include anche Enums . Nessun repo richiesto, solo <100 righe di T4.

Utilizzo
Nessuna libreria, nessun NuGet, solo questo semplice file T4 semplice: usa "aggiungi elemento" in Visual Studio e scegli un modello T4 qualsiasi. Quindi incollalo nel file. Adatta ogni riga con "ACME" al suo interno. Per ogni classe C # aggiungi una riga

<#= Interface<Acme.Duck>() #>

L'ordine è importante, qualsiasi tipo noto verrà utilizzato nelle seguenti interfacce. Se si utilizzano solo interfacce, l'estensione del file può essere .d.ts , per le enumerazioni è necessario un file .ts , poiché viene istanziata una variabile.

Personalizzazione
Hack lo script.

<#@ template debug="true" hostSpecific="true" language="C#" #>
<#@ output extension=".ts" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ assembly name="$(TargetDir)ACME.Core.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Linq" #>

<#= Interface<Acme.Bunny>() #>
<#= Interface<Acme.Duck>() #>
<#= Interface<Acme.Birdy>() #>
<#= Enums<Acme.CarrotGrade>() #>
<#= Interface<Acme.LinkParticle>() #>

<#+  
    List<Type> knownTypes = new List<Type>();

    string Interface<T>()
    {   
        Type t = typeof(T);     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    IEnumerable<MemberInfo> GetInterfaceMembers(Type type)
    {
        return type.GetMembers(BindingFlags.Public | BindingFlags.Instance)
            .Where(mi => mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property);
    }

    string ToCamelCase(string s)
    {
        if (string.IsNullOrEmpty(s)) return s;
        if (s.Length < 2) return s.ToLowerInvariant();
        return char.ToLowerInvariant(s[0]) + s.Substring(1);
    }

    string GetTypeName(MemberInfo mi)
    {
        Type t = (mi is PropertyInfo) ? ((PropertyInfo)mi).PropertyType : ((FieldInfo)mi).FieldType;
        return this.GetTypeName(t);
    }

    string GetTypeName(Type t)
    {
        if(t.IsPrimitive)
        {
            if (t == typeof(bool)) return "bool";
            if (t == typeof(char)) return "string";
            return "number";
        }
        if (t == typeof(decimal)) return "number";            
        if (t == typeof(string)) return "string";
        if (t.IsArray)
        {            
            var at = t.GetElementType();
            return this.GetTypeName(at) + "[]";
        }
        if(typeof (System.Collections.IEnumerable).IsAssignableFrom(t)) 
        {
            var collectionType = t.GetGenericArguments()[0]; // all my enumerables are typed, so there is a generic argument
            return GetTypeName(collectionType) + "[]";
        }            
        if (Nullable.GetUnderlyingType(t) != null)
        {
            return this.GetTypeName(Nullable.GetUnderlyingType(t));
        }
        if(t.IsEnum) return "number";
        if(knownTypes.Contains(t)) return t.Name;
        return "any";
    }

    string Enums<T>() // Enums<>, since Enum<> is not allowed.
    {
        Type t = typeof(T);        
        var sb = new StringBuilder();        
        int[] values = (int[])Enum.GetValues(t);
        sb.AppendLine("var " + t.Name + " = {");
        foreach(var val in values) 
        {
            var name = Enum.GetName(typeof(T), val);
            sb.AppendFormat("{0}: {1},\n", name, val);
        }
        sb.AppendLine("}");
        return sb.ToString();
    }
#>

Il livello successivo dello script consisterà nel creare l'interfaccia del servizio dalla classe MVC JsonController.


1
Molto carino, ma hai typeof(ParticleKind)nel tuo Enum<T>. Sicuramente dovrebbe essere typeof(T)? Inoltre è necessario aggiornare boolper essere booleanper le versioni successive di TypeScript
Gone Coding

Nota anche: questo rompe con le proprietà enum nelle classi
Gone Coding

1. Uhh, sì, grazie per l'avviso, risolverà il problema. 2. Il dattiloscritto si è evoluto dopo aver scritto questo script. Sembra che potrebbe aver bisogno di qualche aggiornamento, hai sicuramente ragione. Spero che serva come punto di partenza per il tuo scopo.
citykid

1
L'ho convertito in una libreria di supporto, ho corretto i bug e ora uso solo voci di una riga nei miei file TT per generare interfacce e nuovi const enums. Grazie per l'esempio. È stato molto vicino e mi ha fatto ottenere un risultato di lavoro molto più velocemente.
Gone Coding

23

Se usi vscode puoi usare la mia estensione csharp2ts che fa esattamente questo.

Basta selezionare il codice C # incollato ed eseguire il Convert C# to TypeScriptcomando dalla tavolozza dei comandi inserisci qui la descrizione dell'immagine Un esempio di conversione:

public class Person
{
    /// <summary>
    /// Primary key
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// Person name
    /// </summary>
    public string Name { get; set; }
}

per

export interface Person
{
    /**Primary key */
    Id : number;

    /**Person name */
    Name : string;
}

1
Penso che le persone siano interessate a una soluzione completamente automatizzata in cui la compilazione con msbuild restituisce le definizioni dei dattiloscritti prima di consumarle. C'è un modo per ottenerlo utilizzando il plugin?
binki

No, questo è un plug-in VSCode, funziona solo all'interno dell'editor e non come programma autonomo
Rafael

Ho convertito questa estensione vscode nel modulo del nodo se lo desideri tramite node.js o tytpescript. Puoi controllare il repo qui: github.com/YuvrajSagarRana/csharp-to-typescript
Sagar Rana Magar

C'è un modo per collegare il comando alla scorciatoia da tastiera? Ad esempio, selezionare il codice .net e impostare shift + ctrl + c per eseguire "Converti C # in TypeScript", velocizzerebbe il processo. Mi piace il plugin!
Pawel Cioch il


18

Se utilizzi Visual Studio, aggiungi l'estensione Typewriter.

Raccolta di Visual Studio

Sito web / Documentazione

Aggiornare

Con Web Essentials installato in VS 2015, è possibile fare clic con il pulsante destro del mouse sul file della classe, quindi> Web Essentials> Crea file Typescript Intellisense dal menu contestuale.


Ha creato il file d.ts per il supporto intellisense ma come si usa e poi qual è il rapporto con la creazione delle classi sottostanti? Sono andato su WebEssentails e non riesco a trovare alcun documento. Eventuali suggerimenti? TIA.
howardlo

@hio Fai semplicemente riferimento al file d.ts in qualsiasi file .ts in cui devi usarlo. Quando / se cambi classe, il file d.ts sottostante verrà aggiornato. (Suggerimento: puoi trascinare e rilasciare il file d.ts file all'inizio di un file .ts e creerà il riferimento per te.)
Michael Tranchida

Grazie Michael! Ho provato a rilasciare il file d.ts in un file .ts vuoto e ha aggiunto solo il file alla cartella contenente. L'ho provato in VS2015 e nel nuovo VS2017, stessi risultati. Conosci qualche video o tutorial che mostra come funziona tutto questo? TIA
howardlo

Ho provato a rilasciare il file d.ts in un file .ts nell'editor e ha creato il riferimento. Penso di aver capito adesso. Tutorial ancora accolto con favore. Grazie!
howardlo

@hlo Spiacente, non conosco nessun tutorial. Quando scelgo il percorso Web Essentials, ho creato file .ts duplicati perché i miei modelli di dominio si trovano in una libreria di classi e nel mio codice lato client, di solito ho bisogno di creare i modelli dto o vm, che il browser deve sapere. Se hai problemi con tutto questo, prova l'estensione Typewriter. Ti permette di avere i tuoi file di modello .ts ovunque tu voglia.
Michael Tranchida

15

Prova il framework Reinforced.Typings. Sembra che risolva il tuo problema.

  1. Installalo da NuGet
  2. Passa al tuo POCO e aggiungi l' [TsInterface]attributo sopra di esso

    using Reinforced.Typings.Attributes;
    namespace YourNamespace {
        [TsInterface]
        public class YourPoco
        {
            public int YourNumber { get;set; }
            public string YourString { get;set; }
            public List<string> YourArray { get;set; }
            public Dictionary<int, object> YourDictionary { get;set; }
        }
    }
  3. Ricostruisci il tuo progetto
  4. Scopri il codice TypeScript generato nel %Your_Project_Directory%/Scripts/project.tsfile e aggiungilo al progetto manualmente

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. Fai lo stesso per tutti i tuoi POCO e fai riferimento project.tsnell'altro codice TypeScript.

Vedi maggiori dettagli nel wiki della documentazione


Aggiungi lo snippet di esempio piuttosto condividendo solo l'URL
Venkat.R

C'è wiki con avvio rapido
Pavel B. Novikov

Ma ok, fornirò un esempio qui :)
Pavel B. Novikov

Nessun supporto .NET Core ( link ) :(
Alex Klaus

5
Il supporto di @AlexKlaus .NET Core è arrivato
Pavel B. Novikov

10

Ho creato una piccola utility in grado di generare interfacce TypeScript da classi C #. È disponibile come pacchetto NuGet . La documentazione dettagliata può essere trovata sulla pagina web del progetto .


Bella biblioteca, buon sforzo. Sfortunatamente non ho trovato un modo per modificare il tipo di valore prodotto, ad esempio convertire "string" in "KnockoutObservableString" o "string []" in "KnockoutObservableArray". È qualcosa che è nei piani del prossimo futuro?
root

2
Ho usato invece T4TS, ci sono voluti 14 minuti.
radice

@root, non dovresti effettivamente convertire una stringa [] in KnockoutObservableArray nelle definizioni generate. Puoi utilizzare queste definizioni generate quando stai effettivamente consumando le istanze serializzate di queste classi. Ora, potresti eseguire l'intero oggetto tramite il plug-in di mappatura, ma ti metterei in guardia contro questo. Questo può essere eccessivo e preferisco sempre convertire manualmente (probabilmente tramite un ctor) dalle tue istanze serializzate di classi C # a classi TypeScript piene di osservabili. L'unica volta che suggerirei di eseguirlo in modo accecante attraverso il plug-in di mappatura è per un'app in stile CRUD.
Allen Rice

@Lukas Kabrt, grazie mille per TypeLite, è stato estremamente vantaggioso nei nostri progetti e ne ho scritto brevemente qui: underwatergorilladome.com/…
Allen Rice

@AllenRice, ho trovato utile avere classi di modelli di visualizzazione Knockout realizzate a mano, che è dove uso l'approccio che hai descritto e lo combino con una classe generata automaticamente che è un DTO che è stato passato attraverso il plugin di mappatura.
root

7

Dai un'occhiata a questa libreria Typewriter

Converte non solo classi, enumerazioni, interfacce, ecc., Ma anche i controller API, il che è semplicemente fantastico ..

Inoltre lo fa non appena salvi il file .cs sorgente, quindi non devo attivare alcuno strumento esterno. Salva .cs e sarai aggiornato .ts


La cosa bella è che produce file TS salvando i file CS corrispondenti. Tuttavia, l'impostazione della cartella di output è piuttosto fragile (vedere la discussione qui ) e richiede del codice artigianale.
Alex Klaus

Uso strumenti di compilazione per questo, e questo strumento è molto più potente della maggior parte menzionato qui
harishr

6

Ho una piccola soluzione che utilizza i modelli T4 ( vedi sorgente ).

Vai da qualsiasi CLR POCO:

public class Parent : Person
{
    public string Name { get; set; }
    public bool? IsGoodParent { get; set; }
    public virtual ICollection<Child> Children { get; set; }
}

A un'interfaccia TypeScript:

///<reference path="Child.d.ts" />
///<reference path="Person.d.ts" />
interface Parent extends Person {
    Name : string;
    IsGoodParent? : bool;
    Children : Child[];
}

3

Puoi utilizzare il progetto open source NSwag : nella GUI, è possibile selezionare la classe .NET da una DLL .NET esistente e generare l'interfaccia TypeScript per essa.

Il progetto fornisce anche strumenti da riga di comando e supporto per modelli T4, nonché generazione di codice client per controller API Web ...


Tieni presente che NSwag genererà file TS solo dai file binari (hai bisogno anche di tutte le dipendenze dei tuoi binari) o dal suo file JSON, che Swagger produce dai file binari.
Alex Klaus

3

Se hai bisogno di creare un file separato per ogni classe / interfaccia TypeScript generata (cioè in un modo "singola classe per file"), puoi provare TypeGen . È uno strumento che puoi utilizzare dalla console di Gestione pacchetti per generare file TypeScript in base alle classi / enumerazioni C #. Attualmente supporta:

  • esportare enumerazioni; esportare POCO come classi o interfacce TS
  • eredità
  • tipi generici
  • tipi di raccolta / raccolta annidata

oltre ad alcune funzionalità aggiuntive. È anche open source (puoi verificarlo su GitHub ).


2

Che ne dici del contrario?

Dai un'occhiata a erecruit TypeScript Translator . Viene fornito con il supporto C # pronto per l'uso, ma in realtà è basato su modelli (utilizza Nunjucks per il rendering), il che significa che può generare qualsiasi altra cosa: VB.NET, F #, C ++, XML, SQL, qualunque cosa tu possa codificare con un modello.

Funziona come un programma console .NET, programma NodeJS (per chi non è su Windows) o come estensione di Visual Studio , completo di funzionalità di generazione al salvataggio. E include il supporto per MSBuild, solo per rendere felice il tuo server di compilazione. :-)


Ho fatto +1 perché è davvero la soluzione migliore, la generazione al salvataggio è la caratteristica killer.
John Zabroski

2

Puoi anche usare questo: https://github.com/pankleks/TypeScriptBuilder

Questa piccola libreria genera la definizione del tipo TypeScript basata sui tipi C #. Usalo direttamente nel tuo progetto backend C # per generare codice per il tuo progetto TypeScript frontend. Puoi anche scrivere una piccola app per console, per generare codice con strumenti di pre-compilazione.

Funziona su framework Full & NET Core!

Installa da nuget: Install-Package TypeScriptBuilder

Funzionalità supportate

  • Risoluzione della dipendenza dal tipo
  • Generics
  • Tipo di ereditarietà
  • Spazi dei nomi (moduli)
  • Enums
  • Tipi nullable
  • Conversione del dizionario (in oggetti indicizzati TS di tipo forte)
  • Set di attributi di controllo della generazione del codice
  • any per i tipi che non possono essere convertiti

Più descrizione: https://github.com/pankleks/TypeScriptBuilder/blob/master/README.md


Ho appena provato TypeScriptBuildere sembra eccellente finora; evviva il supporto di .NET Core!
Tobias J

1

Ragazzi, date un'occhiata a https://github.com/reinforced/ Reinforced.Typings . Ho giocato con i modelli typelite e t4 negli ultimi giorni e ho finito con questo progetto. È semplicissimo e funziona come un fascino. Basta ottenere il pacchetto, modificare il file di configurazione (è come per 10 secondi) e compilare. Tutto viene eseguito automaticamente senza problemi. Benedici l'autore!

La cosa negativa dei modelli T4 è che una volta compilati da VS gli assembly scansionati sono bloccati e devi riavviare VS (quanto è sciocco?). Ci sono alcune soluzioni alternative in T4 Toolbox + alcune direttive di pulizia VS ma nessuna di queste ha funzionato per me.


1

Mi piace la soluzione citykid. L'avevo allungato un po '. Quindi, anche la soluzione si basa sulla tecnica di codegenerazione con modelli T4.

Può generare tipi TypeScript comuni e dichiarazioni ambientali.

Supporta l'ereditarietà e le implementazioni dell'interfaccia.

Supporta generici, array ed elenchi come campi di tipo.

Inoltre si traduce in tipi TypeScript che non sono esplicitamente menzionati nella configurazione (ad esempio importiamo il tipo A, e nell'output di TS puoi trovare altri tipi: tipi di campi, tipi di base e interfacce).

Puoi anche sovrascrivere il nome del tipo.

Sono supportati anche gli enumerativi.

Esempio di utilizzo (puoi trovarlo nel repository del progetto):

// set extension of the generated TS file
<#@ output extension=".d.ts" #>

// choose the type of TS import TsMode.Ambient || TsMode.Class
<# var tsBuilder = new TsBuilder(TsMode.Ambient); #>

// reference assembly with the c# types to be transformed
<#@ assembly name="$(SolutionDir)artifacts\...\CsT4Ts.Tests.dll" #>

// reference namespaces
<#@ import namespace="CsT4Ts.Tests" #>
<#
    //add types to processing
    tsBuilder.ConsiderType(typeof(PresetDTOBase), "PresetBase");
    tsBuilder.ConsiderType(typeof(PresetDTO), "Preset");
    tsBuilder.ConsiderType(typeof(TestInterface<,>));
#>

// include file with transformation algorithms
<#@ include file="CsT4Ts.t4" #>

E otterrai un output

//CsT4Ts.Tests.PresetDTOBase => PresetBase
// CsT4Ts.Tests.PresetDTO => Preset
// CsT4Ts.Tests.TestInterface`2 => TestInterface
// CsT4Ts.Tests.TestEnum => TestEnum

declare class PresetBase
{
    PresetId: string;
    Title: string;
    InterviewDate: string;
}

declare class Preset extends PresetBase
{
    QuestionsIds: string[];
}

declare interface TestInterface<TA, TB>
{
    A: string;
    B: number;
    C: TestEnum;
    D: TestEnum[];
    E: number[];
    F: TA;
    G: TB[];
}

declare enum TestEnum
{
    Foo = 10,
    Boo = 100
}

Controlla la soluzione completa qui: https://bitbucket.org/chandrush/cst4ts


1

Puoi anche usare Bridge.net. Dalla versione 1.7 supporta la generazione di definizioni TypeScript per i tipi C #. Vedi http://bridge.net/docs/generate-typescript-definitions/


Il problema principale è che quando esegui una ricerca su Google potresti atterrare alla domanda originale e non notare mai che esistono informazioni utili in una risposta duplicata / chiusa
George Birbilis

Quindi assicurati che il canonico abbia le migliori informazioni. Non pubblicare su più domande. Qualsiasi ulteriore discussione su questo può essere portata su Meta Stack Overflow
Martijn Pieters

1

Mi è piaciuta molto anche la risposta di @ citykid, quindi l'ho estesa per fare un intero spazio dei nomi alla volta. Basta inserire le classi POCO nello spazio dei nomi e ricostruire i modelli T4. Vorrei sapere come generare file separati per ciascuno, ma non è la fine del mondo.

Devi fare riferimento ai file .DLL nella parte superiore (dove sono le classi che desideri) e devi menzionare gli spazi dei nomi. Tutte le righe da modificare sono contrassegnate con ACME. Grandi complimenti a @citykid, apprezzatelo!

<#@ template debug="true" hostSpecific="true" language="C#" #>
<#@ output extension=".ts" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ assembly name="$(TargetDir)YOUR_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>

<#= Process("My.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>

<#+  

    List<Type> knownTypes = new List<Type>();

    string Process(string nameSpace) {
      var allass = AppDomain.CurrentDomain.GetAssemblies();
      var ss = "";
      foreach (var ass in allass)
      {
         ss += ProcessAssembly(ass, nameSpace);
      }
      return ss;
    }

   string ProcessAssembly(Assembly asm, string nameSpace) {
      try {
            Type[] types;
            try
            {
                types = asm.GetTypes();
            }
            catch (ReflectionTypeLoadException e)
            {
                types = e.Types;
            }
            var s = "";
            foreach (var t in types.Where(t => t != null))
            {
               try {

               if (String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal))
               {
                    s += InterfaceOfType(t);
               }

               } catch (Exception e)
               {
               }
            }
            return s;      
      }
      catch (Exception ee2) {
        return "// ERROR LOADING TYPES: " + ee2;
      }

   }

    string InterfaceOfType(Type T)
    {   
        Type t = T;     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\r\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\r\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    string Interface<T>()
    {   
        Type t = typeof(T);     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\r\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    IEnumerable<MemberInfo> GetInterfaceMembers(Type type)
    {
        return type.GetMembers(BindingFlags.Public | BindingFlags.Instance)
            .Where(mi => mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property);
    }

    string ToCamelCase(string s)
    {
        if (string.IsNullOrEmpty(s)) return s;
        if (s.Length < 2) return s.ToLowerInvariant();
        return char.ToLowerInvariant(s[0]) + s.Substring(1);
    }

    string GetTypeName(MemberInfo mi)
    {
        Type t = (mi is PropertyInfo) ? ((PropertyInfo)mi).PropertyType : ((FieldInfo)mi).FieldType;
        return this.GetTypeName(t);
    }

    string GetTypeName(Type t)
    {
        if(t.IsPrimitive)
        {
            if (t == typeof(bool)) return "boolean";
            if (t == typeof(char)) return "string";
            return "number";
        }
        if (t == typeof(decimal)) return "number";            
        if (t == typeof(string)) return "string";
        if (t.IsArray)
        {            
            var at = t.GetElementType();
            return this.GetTypeName(at) + "[]";
        }
        if(typeof (System.Collections.IEnumerable).IsAssignableFrom(t)) 
        {
            var collectionType = t.GetGenericArguments()[0]; // all my enumerables are typed, so there is a generic argument
            return GetTypeName(collectionType) + "[]";
        }            
        if (Nullable.GetUnderlyingType(t) != null)
        {
            return this.GetTypeName(Nullable.GetUnderlyingType(t));
        }
        if(t.IsEnum) return "number";
        if(knownTypes.Contains(t)) return t.Name;
        return "any";
    }

    string Enums<T>() // Enums<>, since Enum<> is not allowed.
    {
        Type t = typeof(T);        
        var sb = new StringBuilder();        
        int[] values = (int[])Enum.GetValues(t);
        sb.AppendLine("var " + t.Name + " = {");
        foreach(var val in values) 
        {
            var name = Enum.GetName(typeof(T), val);
            sb.AppendFormat("{0}: {1},\r\n", name, val);
        }
        sb.AppendLine("}");
        return sb.ToString();
    }
#>

0

La mia soluzione era scrivere un piccolo util codegen che prende semplicemente un assembly del progetto (e gli assembly di riferimento) e inizia la scansione dei tipi che sono coinvolti nell'interazione tra dattiloscritto e c #. Questo util emette sia javascript come d.ts ... Lo strumento viene chiamato nell'evento post-build ... funziona a meraviglia!


Non so perché ho scelto di emettere js e d.ts ... in questo momento semplicemente restituisce .ts ... semplice e molto fattibile.
Paul 0515

1
Ciao Paul ... potresti condividere il codice util con noi. Sto cercando di creare solo un file ts (in una determinata posizione della cartella) e non un file d.ts come hai detto tu. È qualcosa che può fare la tua utility?
Krishna Teja Veeramachaneni

0

Se sei interessato, puoi usare TypedRpc . Il suo scopo non è solo creare le interfacce in TypeScript, ma creare tutte le comunicazioni con il servizio in .Net utilizzando il protocollo JsonRpc.

Esempio per una classe nel server:

[TypedRpc.TypedRpcHandler]
public class RpcServerExample
{
    public String HelloWorld()
    {
        return "Hello World!";
    }
}

Utilizzo del codice TypeScript generato:

/// <reference path="Scripts/TypedRpc.ts" />

let rpc: TypedRpc.RpcServerExample = new TypedRpc.RpcServerExample();

var callback = function(data, jsonResponse) {
    console.log(data);
};

rpc.HelloWorld().done(callback).fail(callback);

Dai un'occhiata a https://github.com/Rodris/TypedRpc per altri esempi di come usarlo.


0

I generatori di client API Web ASP.NET possono essere più utili, meno sovraccarico rispetto alla toolchain spavalda e altri durante SDLC.

Sebbene i programmatori generalmente utilizzino WebApiClientGen per generare codici API client, questo progetto fornisce anche POCO2TS.exe, un programma a riga di comando che genera interfacce TypsScript dalle classi POCO. Puoi utilizzare Poco2ts.exe o il componente poco2ts per integrare la generazione del codice con la tua pipeline di build.


0

Se vuoi convertirlo tramite node.js, puoi usare questo pacchetto (csharp-to-typescript). https://www.npmjs.com/package/csharp-to-typescript

codice sorgente: https://github.com/YuvrajSagarRana/csharp-to-typescript

eg: 
// After installation, import the package.
var { CsharpToTs, getConfiguration } = require("csharp-to-typescript");

// Use CsharpToTs to convert your source code a. Method one give your source code as string:
const sourceCodeInString =   `public class Address
{
  public int Id {get; set;}
  public string Street { get; set; }
  public string City { get; set; }
}`

var outputTypescript = CsharpToTs(sourceCodeInString, getConfiguration());
console.log(outputTypescript);

// Output is

export class Address
{
  Id: number;
  Street: string;
  City: string;
}

0

Se stai usando VSCode, potresti dare un'occhiata a quell'estensione C # a TypeScript

Converti la classe C # nell'interfaccia TypeScript

Guarda come posso convertirlo da codice C # con un solo clic. Naturalmente, non tutte le classi verranno convertite come la fabbrica, ma è abbastanza buono per il lato client. Abbiamo solo bisogno della forma dei dati. A volte, se ho bisogno di utilizzare il motivo visitatore, decorerò con metodi aggiuntivi di cui ho bisogno. Ci sono voluti solo 5 secondi per farlo. Confrontando con un minuto sopra, potrei dire che è una grande vittoria.

Vedi più dettagli nel mio post sul blog

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.