Jak ponownie używać istniejących definicji klas C # w projektach TypeScript

121

Mam zamiar zacząć używać TypeScriptw moim projekcie klienta HTML, który należy do projektu MVC z już istniejącym modelem domeny platformy jednostki. Chcę, aby moje dwa projekty (po stronie klienta i po stronie serwera) były całkowicie oddzielone, ponieważ dwa zespoły będą nad tym pracować ... JSON i REST są używane do komunikacji obiektów w tę iz powrotem.

Oczywiście moje domainobiekty po stronie klienta powinny pasować do obiektów po stronie serwera. W przeszłości zwykle robiłem to ręcznie. Czy istnieje sposób ponownego użycia definicji klas języka C # (szczególnie POJOklas w modelu domeny) w celu utworzenia odpowiednich klas w języku TypeScript ”?

pabloelustondo
źródło
Nie, to zupełnie inne języki.
Hans Passant
6
Tak, miałem na myśli POCO. Wiem, że są to zupełnie inne języki ... ale byłoby wspaniale uniknąć pisania tego wszystkiego ponownie ... Myślę, że na razie skopiuję i wkleję mój kod C # ... i zrefaktoruję wszystko, aż się skompiluje TypeScript ... w ten sposób jestem pewien, że nie wpisałem źle atrybutu ... i pomóż mi nie pamiętać. Ale to najwyraźniej wcale nie brzmi ładnie.
pabloelustondo
1
Interesuje mnie również inny kierunek - od klas modeli Typescript do klas modeli C #, dwukierunkowo deserializowalnych przez JSON.
Jason Kleban,
Szukałem tego samego i właśnie natknąłem się na tę wtyczkę Gulp, chociaż nie wiem, jakie jest dla niej wsparcie
Luke T O'Brien

Odpowiedzi:

54

Obecnie nie ma niczego, co zamapuje C # na TypeScript. Jeśli masz dużo POCO lub myślisz, że mogą się one często zmieniać, możesz stworzyć konwerter - coś prostego na wzór ...

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

Do

export class MyPoco {
    public Name: string;
}

Istnieje również dyskusja w Codeplex o automatycznym generowaniu z C # .

Aby zachować aktualność, TypeLite może generować interfejsy TypeScript z C #:

http://type.litesolutions.net/

Fenton
źródło
Tak, coś takiego myślałem o zrobieniu ręcznie ... dobrze. Nie jestem pewien, czy mam teraz czas na napisanie konwertera… ale tak, to byłby pomysł. Dzięki. Być może Microsoft właśnie to robi właśnie teraz, o czym mówimy.
pabloelustondo
Możesz to zrobić na dwa sposoby ... Wygeneruj pliki .ts przy pomocy EnvDTE Automation lub używając Mef Directory Catalog i Reflection / Introspection. Wolę ten drugi, bo nie zależy od wyglądu.
Arek Bal
1
Zacząłem używać dart i natknąłem się na ten sam problem, jak udostępniać typy między C # i JavaScript. Miałem nadzieję, że ten problem zostanie rozwiązany przez Typescript, ale wygląda na to, że odpowiedź jeszcze nie jest. Byłem też trochę zepsuty przez kompilator saltarelle, który skompilował c # do javascript raczej ładnie saltarelle-compiler.com
BraveNewMath
2
@DanielHarvey Enum są generowane poprawnie przez TypeLite, prawdopodobnie naprawione od czasu twojego komentarza.
pauloya,
1
TypeScriptPaste przekonwertuje C # naTypescript. Musisz mieć kompilator Roslyn, czyli Visual Studio 2015, ale działa naprawdę dobrze. To nie jest w 100% i musiałem zmylić trochę kodu - na przykład konwertowanie foreach na pętle for, pisanie własnej klasy List <T>, na przykład, musisz nadać kodowi taką strukturę, aby był `` czysty '' z tylko wewnętrznymi strukturami danych do współpracować, ale była to niewielka cena za możliwość modyfikowania i testowania kodu w VS, a następnie „kompilacji” go do JavaScript za pomocą TypeScript.
John Mott
36

Oprogramowanie Web Essentials umożliwia kompilowanie plików C # do .d.tsplików TypeScript przy zapisywaniu. Następnie możesz odwołać się do definicji z .tsplików.

wprowadź opis obrazu tutaj

VB
źródło
Czy może mylisz pliki .ts i C #? nie mogę znaleźć tej opcji
Flores
1
Ale po kilku poszukiwaniach odkryłem, co masz na myśli… właściwie całkiem przydatne.
Flores,
2
Właściwie to nie jest, jestem pewien, że operacja nic nie kompiluje, generuje kod. To mnie zdezorientowało, ale nie jest w 99% poprawne, dam ci to ;-)
Flores
1
Byłoby bardziej przydatne, gdybyśmy mogli skonfigurować jego przestrzeń nazw i pewne dostosowania.
Farshid Saberi
5
Aby z niego skorzystać, musisz teraz ręcznie zainstalować „Generator definicji języka TypeScript” - zobacz tutaj
Taran
24

TypeLite i T4TS powyżej oba wyglądały dobrze, po prostu wybrałem jeden, TypeLite, rozwidlił go, aby uzyskać wsparcie

  • ValueTypes ,
  • Nullables
  • camelCasing (główna dokumentacja języka TypeScript używa wielbłądów, a to idzie zbyt dobrze razem z C #)
  • pola publiczne (uwielbiają czyste i czytelne POCO, ułatwiają również kompilatorowi C #)
  • wyłącz generowanie modułów

Potem potrzebowałem interfejsów C # i pomyślałem, że nadszedł czas, aby upiec własne rzeczy i napisałem prosty skrypt T4, który po prostu robi to, czego potrzebuję. Obejmuje również wyliczenia . Nie jest wymagane repozytorium, tylko <100 linii T4.

Użycie
Brak biblioteki, brak pakietu NuGet, tylko ten zwykły, prosty plik T4 - użyj opcji „dodaj element” w programie Visual Studio i wybierz dowolny szablon T4. Następnie wklej to do pliku. Dostosuj każdą linię z „ACME” w niej. Dla każdej klasy C # dodaj linię

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

Kolejność ma znaczenie, każdy znany typ zostanie użyty w kolejnych interfejsach. Jeśli używasz tylko interfejsów, rozszerzenie pliku może być .d.ts , dla wyliczeń potrzebny jest plik .ts , ponieważ tworzona jest instancja zmiennej.

Dostosowywanie
Zhakuj skrypt.

<#@ 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();
    }
#>

Kolejnym poziomem skryptu będzie stworzenie interfejsu usługi z klasy MVC JsonController.

citykid
źródło
1
Bardzo urocze, ale masz typeof(ParticleKind)w swoim Enum<T>. Z pewnością tak powinno być typeof(T)? Musisz także zaktualizować, boolaby być booleandla późniejszych wersji TypeScript
Gone Coding
Uwaga: to zrywa z właściwościami wyliczenia w klasach
Gone Coding
1. Uhh, tak, dziękuję za ostrzeżenie, naprawię to. 2. Maszynopis ewoluował od czasu napisania tego skryptu. Wygląda na to, że może wymagać aktualizacji, na pewno masz rację. Mam nadzieję, że posłuży jako punkt wyjścia do twoich własnych celów.
citykid
1
Przekształciłem go w bibliotekę pomocniczą, naprawiłem błędy i teraz używam tylko jednowierszowych wpisów w moich plikach TT do generowania interfejsów i nowych plików const enum. Dzięki za przykład. Było bardzo blisko i znacznie szybciej dało mi wynik pracy.
Gone Coding
24

Jeśli używasz vscode, możesz użyć mojego rozszerzenia csharp2ts, które robi dokładnie to.

Wystarczy zaznaczyć wklejony kod C # i uruchomić Convert C# to TypeScriptpolecenie z palety poleceń wprowadź opis obrazu tutaj Przykład konwersji:

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

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

do

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

    /**Person name */
    Name : string;
}
Rafael
źródło
1
Myślę, że ludzie są zainteresowani w pełni zautomatyzowanym rozwiązaniem, w którym kompilacja za pomocą msbuild wyświetla definicje maszynopisu przed ich użyciem. Czy jest sposób, aby to uzyskać za pomocą wtyczki?
binki
Nie, to wtyczka VSCode, działa tylko w edytorze, a nie jako samodzielny program
Rafael
Przekonwertowałem to rozszerzenie vscode na moduł węzłowy, jeśli chcesz za pośrednictwem node.js lub tytpescript. Możesz sprawdzić repozytorium tutaj: github.com/YuvrajSagarRana/csharp-to-typescript
Sagar Rana Magar
Czy istnieje sposób na połączenie polecenia ze skrótem klawiaturowym? Na przykład wybranie kodu .net i skonfigurowanie shift + ctrl + c w celu wykonania „Convert C # to TypeScript” przyspieszy proces. Podoba mi się wtyczka!
Paweł Cioch
18

Oto moje podejście do rozwiązania tego problemu. Zadeklaruj swoje klasy C # z atrybutem, a pliki .d.ts zostaną wygenerowane (przy użyciu transformacji T4). W witrynie nuget znajduje się pakiet, a źródło jest dostępne na github . Nadal pracuję nad projektem, ale wsparcie jest dość obszerne.

Christoffer
źródło
Rozwidliłem
Frank.Germain
18

Jeśli używasz programu Visual Studio, dodaj rozszerzenie Maszyna do pisania.

Galeria programu Visual Studio

Witryna internetowa / Dokumentacja

Aktualizacja

Po zainstalowaniu programu Web Essentials w programie VS 2015 można kliknąć prawym przyciskiem myszy plik klasy, a następnie z menu kontekstowego wybrać> Web Essentials> Utwórz plik Typescript Intellisense.

Michael Tranchida
źródło
Stworzył plik d.ts do obsługi Intellisense, ale jak go używać i jaki jest związek z tworzeniem podstawowych klas? Poszedłem do WebEssentails i nie mogę znaleźć żadnych dokumentów. Jakieś sugestie? TIA.
howardlo
@hio Po prostu odwołaj się do pliku d.ts w jakimkolwiek pliku .ts, w którym chcesz go użyć. Gdy / jeśli zmienisz klasę, podstawowy plik d.ts zostanie zaktualizowany. (Wskazówka: możesz przeciągnąć i upuścić plik d.ts plik na początek pliku .ts i utworzy odniesienie dla Ciebie.)
Michael Tranchida,
Dzięki Michael! Próbowałem upuścić plik d.ts do pustego pliku .ts i tylko dodałem plik do folderu zawierającego. Wypróbowałem to w VS2015 i nowym VS2017, te same wyniki. Czy znasz jakiś film lub samouczek, który pokazuje, jak to wszystko działa? TIA
howardlo,
Próbowałem upuścić plik d.ts do pliku .ts w edytorze i utworzyłem odniesienie. Myślę, że teraz rozumiem. Samouczek nadal mile widziany. Dzięki!
howardlo,
@hlo Przepraszamy, nie znam żadnych samouczków. Kiedy idę ścieżką Web Essentials, tworzę zduplikowane pliki .ts, ponieważ moje modele domeny znajdują się w bibliotece klas, a w kodzie po stronie klienta zwykle muszę utworzyć modele dto lub vm, które przeglądarka musi wiedzieć o. Jeśli masz z tym wszystkim problemy, wypróbuj rozszerzenie Maszyna do pisania. Pozwala na przechowywanie plików modelu ur .ts w dowolnym miejscu.
Michael Tranchida,
15

Wypróbuj framework Reinforced.Typings. Wygląda na to, że to rozwiązuje Twój problem.

  1. Zainstaluj go z NuGet
  2. Przejdź do swojego POCO i dodaj [TsInterface]atrybut nad nim

    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. Odbuduj swój projekt
  4. Znajdź wygenerowany kod TypeScript w %Your_Project_Directory%/Scripts/project.tspliku i dodaj go do projektu ręcznie

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. Zrób to samo dla wszystkich POCO i referencji project.ts w innym kodzie TypeScript.

Zobacz więcej szczegółów w dokumentacji wiki

Pavel B. Novikov
źródło
Dodaj przykładowy fragment
kodu,
Ale ok, podam tutaj przykład :)
Pavel B. Novikov
Brak obsługi .NET Core ( link ) :(
Alex Klaus
5
Wsparcie @AlexKlaus .NET Core jest już dostępne
Pavel B. Novikov
10

Stworzyłem małe narzędzie, które może generować interfejsy TypeScript z klas C #. Jest dostępny jako pakiet NuGet . Szczegółową dokumentację można znaleźć na stronie projektu .

Lukas Kabrt
źródło
Ładna biblioteka, dobry wysiłek. Niestety nie znalazłem sposobu na modyfikację typu wartości, np. Przekonwertowanie „string” na „KnockoutObservableString” lub „string []” na „KnockoutObservableArray”. Czy jest to coś, co jest w planach na najbliższą przyszłość?
rootowanie
2
Zamiast tego użyłem T4TS, zajęło to 14 minut.
root
@root, w generowanych definicjach nie należy właściwie konwertować ciągu znaków [] na KnockoutObservableArray. Używasz tych wygenerowanych definicji, gdy faktycznie używasz serializowanych wystąpień tych klas. Możesz teraz uruchamiać cały obiekt przez wtyczkę mapującą, ale ostrzegałbym przed tym. To może być przesadne i zawsze wolę ręcznie konwertować (prawdopodobnie za pomocą kontrolera) z serializowanych wystąpień klas C # do klas TypeScript pełnych obserwabli. Jedyny raz, kiedy zasugerowałbym oślepiające uruchomienie go przez wtyczkę mapującą, dotyczy aplikacji w stylu CRUD.
Allen Rice
@Lukas Kabrt, bardzo dziękuję za TypeLite, okazał się niezwykle korzystny w naszych projektach i pisałem o tym krótko tutaj: podwodnegorilladome.com/…
Allen Rice
@AllenRice, przydało mi się mieć ręcznie wykonane klasy modelu widoku Knockout, w których używam podejścia, które opisałeś, i łączę je z automatycznie generowaną klasą, która jest DTO, która została przesłana przez wtyczkę mapującą.
root
7

Proszę spojrzeć na tę bibliotekę Maszyna do pisania

Konwertuje nie tylko klasy, wyliczenia, interfejsy itp., Ale także kontrolery API, co jest po prostu niesamowite.

Dodatkowo robi to zaraz po zapisaniu źródłowego pliku .cs, więc nie muszę uruchamiać żadnego zewnętrznego narzędzia. Zapisz plik .cs, a otrzymasz zaktualizowany plik .ts

harishr
źródło
Wspaniałą rzeczą jest to, że tworzy pliki TS podczas zapisywania odpowiednich plików CS. Jednak ustawienie folderu wyjściowego jest dość delikatne (zobacz dyskusję tutaj ) i wymaga trochę ręcznie spreparowanego kodu.
Alex Klaus
Używam do tego narzędzi do kompilacji, a to narzędzie jest o wiele potężniejsze niż większość wymienionych tutaj
harishr
6

Mam małe rozwiązanie, które wykorzystuje szablony T4 ( zobacz źródło ).

Idziesz z dowolnego CLR POCO:

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

Do interfejsu TypeScript:

///<reference path="Child.d.ts" />
///<reference path="Person.d.ts" />
interface Parent extends Person {
    Name : string;
    IsGoodParent? : bool;
    Children : Child[];
}
diachedelic
źródło
3

Możesz użyć projektu NSwag typu open source : w GUI możesz wybrać klasę .NET z istniejącej biblioteki DLL .NET i wygenerować dla niej interfejs TypeScript.

Projekt zapewnia również narzędzia wiersza poleceń i obsługę szablonów T4, a także generowanie kodu klienta dla kontrolerów Web API ...

Rico Suter
źródło
Należy pamiętać, że NSwag wygeneruje pliki TS tylko z plików binarnych (potrzebujesz również wszystkich zależności swoich plików binarnych) lub z pliku JSON, który Swagger tworzy z plików binarnych.
Alex Klaus
3

Jeśli chcesz utworzyć oddzielny plik dla każdej wygenerowanej klasy / interfejsu TypeScript (tj. W sposób „pojedyncza klasa na plik”), możesz wypróbować TypeGen . Jest to narzędzie, którego można używać z poziomu konsoli Menedżera pakietów do generowania plików TypeScript na podstawie klas / wyliczeń C #. Obecnie obsługuje:

  • eksportowanie wyliczeń; eksportowanie POCO jako klas TS lub interfejsów
  • dziedzictwo
  • typy ogólne
  • kolekcja / zagnieżdżone typy kolekcji

plus kilka dodatkowych funkcji. Jest to również open source (możesz to sprawdzić na github ).

JB1
źródło
2

A co na odwrót?

Sprawdź erecruit TypeScript Translator . Jest wyposażony w gotową obsługę C #, ale w rzeczywistości jest oparty na szablonach (używa Nunjucks do renderowania), co oznacza, że ​​może generować wszystko inne - VB.NET, F #, C ++, XML, SQL - wszystko, co możesz zakodować za pomocą szablonu.

Działa jako program konsoli .NET, program NodeJS (dla tych spoza systemu Windows) lub jako rozszerzenie programu Visual Studio , wraz z funkcją generowania przy zapisywaniu. Obejmuje również obsługę MSBuild, aby Twój serwer kompilacji był zadowolony. :-)

Fyodor Soikin
źródło
Dałem +1, ponieważ jest to naprawdę najlepsze rozwiązanie, a funkcja generowania przy zapisie jest zabójcza.
John Zabroski
2

Możesz również użyć tego: https://github.com/pankleks/TypeScriptBuilder

Ta mała biblioteka generuje definicję typu TypeScript na podstawie typów C #. Użyj go bezpośrednio w projekcie C # zaplecza, aby wygenerować kod dla projektu frontendowego TypeScript. Możesz również napisać małą aplikację konsolową, aby wygenerować kod za pomocą narzędzi do kompilacji wstępnej.

Działa na platformie Full & NET Core!

Zainstaluj przez nuget: Install-Package TypeScriptBuilder

Obsługiwane funkcje

  • Rozwiązywanie zależności typu
  • Generics
  • Dziedziczenie typów
  • Przestrzenie nazw (moduły)
  • Wyliczenia
  • Typy zerowe
  • Konwergencja słownika (do obiektów indeksowanych TS silnego typu)
  • Zestaw atrybutów kontroli generowania kodu
  • any dla typów, których nie można konwertować

Więcej opisu: https://github.com/pankleks/TypeScriptBuilder/blob/master/README.md

pankleks
źródło
Właśnie wypróbowałem TypeScriptBuilderi na razie wygląda świetnie; brawo za wsparcie .NET Core!
Tobias J
1

Chłopaki spójrz na https://github.com/reinforced/ Reinforced.Typings . Bawiłem się szablonami Typelite i T4 przez ostatnie kilka dni i skończyłem z tym projektem. Jest bardzo prosty i działa jak urok. Po prostu pobierz pakiet, zmodyfikuj plik konfiguracyjny (jest to około 10 sekund) i zbuduj. Wszystko odbywa się automatycznie, bez żadnych problemów. Pobłogosław autora!

Wadą szablonów T4 jest to, że po skompilowaniu z VS zeskanowane zestawy są zablokowane i trzeba ponownie uruchomić VS (jakie to głupie?). Istnieją pewne obejścia w T4 Toolbox + niektóre dyrektywy czyszczenia VS, ale żadna z nich nie zadziałała.

veb
źródło
1

Podoba mi się rozwiązanie citykid. Trochę go przedłużyłem. Tak więc rozwiązanie jest również oparte na technice kodegeneracji z szablonami T4.

Może generować typowe typy TypeScript i deklaracje otoczenia.

Obsługuje dziedziczenie i implementacje interfejsów.

Obsługuje typy ogólne, tablice i listy jako pola typu.

Przekłada się również na typy TypeScript, które nie są wyraźnie wymienione w konfiguracji (na przykład importujemy typ A, aw wynikach TS można znaleźć inne typy: typy pól, typy podstawowe i interfejsy).

Możesz także zastąpić nazwę typu.

Obsługiwane są również wyliczenia.

Przykład użycia (można go znaleźć w repozytorium projektu):

// 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" #>

Otrzymasz wynik

//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
}

Sprawdź pełne rozwiązanie tutaj: https://bitbucket.org/chandrush/cst4ts

RollingStone
źródło
1

Możesz także użyć Bridge.net. Od wersji 1.7 obsługuje generowanie definicji TypeScript dla typów C #. Zobacz http://bridge.net/docs/generate-typescript-definitions/

George Birbilis
źródło
Główny problem polega na tym, że gdy wyszukujesz w Google, możesz
trafić
Dlatego upewnij się, że kanonik zawiera najlepsze informacje. Nie publikuj na wielu pytaniach. Dalszą dyskusję na ten temat można skierować do Meta Stack Overflow
Martijn Pieters
1

Bardzo podobała mi się również odpowiedź @ citykid, więc rozszerzyłem ją tak, aby zajmowała się jednocześnie całą przestrzenią nazw. Po prostu umieść klasy POCO w przestrzeni nazw i przebuduj szablony T4. Chciałbym wiedzieć, jak wygenerować osobne pliki dla każdego, ale to nie koniec świata.

Musisz odwołać się do plików .DLL w górnej części (tam, gdzie chcesz, aby klasy) i musisz wspomnieć o przestrzeniach nazw. Wszystkie linie do edycji są oznaczone ACME. Wielkie cuda dla @citykid, doceniam to!

<#@ 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();
    }
#>
user230910
źródło
0

Moim rozwiązaniem było napisanie małego narzędzia do kodowania, które po prostu pobiera zestaw projektu (i odwołuje się do zestawów) i rozpoczyna skanowanie typów, które są zaangażowane w interakcję między skryptem maszynowym a językiem C #. To narzędzie generuje zarówno javascript jako d.ts ... To narzędzie jest wywoływane w zdarzeniu post-build ... działa jak urok!

Paul0515
źródło
Nie wiem, dlaczego zdecydowałem się wypisać js i d.ts ... teraz po prostu wyświetla .ts ... proste i bardzo wykonalne.
Paul0515,
1
Cześć Paul ... czy mógłbyś podzielić się z nami kodem użytkowym. Chcę po prostu utworzyć plik ts (w określonej lokalizacji folderu), a nie plik d.ts, jak powiedziałeś. Czy to coś, co może zrobić twój utylizator?
Krishna Teja Veeramachaneni
0

Jeśli jesteś zainteresowany, możesz użyć TypedRpc . Jego celem jest nie tylko tworzenie interfejsów w języku TypeScript, ale tworzenie całej komunikacji z usługą w .Net przy użyciu protokołu JsonRpc.

Przykład zajęć na serwerze:

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

Wykorzystanie wygenerowanego kodu TypeScript:

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

Sprawdź https://github.com/Rodris/TypedRpc, aby zobaczyć inne przykłady, jak z niego korzystać.

Rodris
źródło
0

Generatory klientów ASP.NET Web API mogą być wygodniejsze i mniej obciążać niż Swagger Toolchain i inne podczas SDLC.

Podczas gdy programiści generalnie używają WebApiClientGen do generowania kodów API klienta, ten projekt zapewnia również POCO2TS.exe, program wiersza polecenia, który generuje interfejsy TypsScript z klas POCO. Możesz użyć Poco2ts.exe lub komponentu poco2ts, aby zintegrować generowanie kodu z potokiem kompilacji.

ZZZ
źródło
0

Jeśli chcesz przekonwertować go za pomocą node.js, możesz użyć tego pakietu (csharp-to-typescript). https://www.npmjs.com/package/csharp-to-typescript

kod źródłowy: 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;
}
Sagar Rana Magar
źródło
0

Jeśli używasz VSCode, możesz rzucić okiem na to rozszerzenie C # do TypeScript

Konwertuj klasę C # na interfejs TypeScript

Zobacz, jak mogę przekonwertować go z kodu C # jednym kliknięciem. Oczywiście nie wszystkie klasy zostaną przekonwertowane, tak jak fabryka, ale jest to wystarczająco dobre dla klienta. Potrzebujemy tylko kształtu danych. Czasami, jeśli potrzebuję użyć wzoru gościa, ozdobię dodatkowymi metodami, których potrzebuję. Zajęło to tylko 5 sekund. W porównaniu z minutą powyżej, mogę powiedzieć, że to duża wygrana.

Zobacz więcej szczegółów w moim poście na blogu

trungk18
źródło