Cara menggunakan kembali definisi kelas C # yang ada dalam proyek TypeScript

121

Saya baru saja akan mulai menggunakan TypeScriptproyek klien HTML saya yang termasuk dalam proyek MVC dengan model domain kerangka entitas yang sudah ada. Saya ingin dua proyek saya (sisi klien dan sisi server) benar-benar terpisah karena dua tim akan mengerjakan ini ... JSON dan REST digunakan untuk mengkomunikasikan objek bolak-balik.

Tentu saja, domainobjek saya di sisi klien harus cocok dengan objek di sisi server. Dulu, saya biasanya melakukannya secara manual. Apakah ada cara untuk menggunakan kembali definisi kelas C # saya (khususnya POJOkelas dalam model domain saya) untuk membuat kelas yang sesuai di TypeScript "?

pabloelustondo
sumber
Tidak, mereka adalah bahasa yang sangat berbeda.
Hans Passant
6
Ya, maksud saya POCO. Saya tahu bahasa mereka benar-benar berbeda ... tetapi akan sangat bagus untuk menghindari mengetik semua ini lagi ... Saya pikir untuk saat ini saya akan menyalin dan menempel kode c # saya .. dan akan merefaktor apa pun hingga terkompilasi di TypeScript ... dengan cara itu saya yakin saya tidak salah mengetik atribut .. dan membantu saya untuk tidak mengingatnya. Tapi ini jelas tidak terdengar bagus sama sekali.
pabloelustondo
1
Saya juga tertarik pada arah lain - dari kelas model Typecript ke kelas model C #, secara dua arah dapat dideserialisasi melalui JSON.
Jason Kleban
Saya telah mencari yang sama dan saya baru saja menemukan plugin Gulp ini meskipun saya tidak tahu berapa banyak dukungan yang ada untuk itu
Luke T O'Brien

Jawaban:

54

Saat ini tidak ada apa pun yang akan memetakan C # ke TypeScript. Jika Anda memiliki banyak POCO atau menurut Anda mungkin sering berubah, Anda dapat membuat konverter - sesuatu yang sederhana di sepanjang ...

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

Untuk

export class MyPoco {
    public Name: string;
}

Ada juga diskusi di Codeplex tentang pembuatan otomatis dari C # .

Hanya untuk terus memperbarui, TypeLite dapat menghasilkan antarmuka TypeScript dari C #:

http://type.litesolutions.net/

Fenton
sumber
Yeahp, hal seperti inilah yang saya pikirkan untuk dilakukan secara manual .. bagus. Tidak yakin saya punya waktu untuk menulis konverter sekarang .. tapi ya, itulah idenya. Terima kasih. Mungkin Microsoft baru saja melakukannya sekarang seperti yang kita bicarakan.
pabloelustondo
Anda dapat melakukan ini dengan salah satu dari dua cara ... Hasilkan file .ts dengan bantuan Otomasi EnvDTE atau dengan menggunakan Katalog Direktori Mef dan Refleksi / Introspeksi. Saya lebih suka yang kedua karena tidak bergantung pada visual.
Arek Bal
1
Saya mulai menggunakan dart dan mengalami masalah yang sama tentang cara berbagi tipe antara c # dan javascript. Saya berharap masalah ini akan diselesaikan dengan Typecript, tetapi sepertinya jawabannya belum. Saya juga sedikit dimanjakan oleh saltarelle-compiler yang mengkompilasi c # ke javascript dengan cukup baik saltarelle-compiler.com
BraveNewMath
2
@DanielHarvey Enum dibuat dengan benar oleh TypeLite, mungkin sudah diperbaiki sejak komentar Anda.
pauloya
1
TypeScriptPaste akan mengubah C # menjadiTypescript. Anda harus memiliki kompiler Roslyn, yang berarti Visual Studio 2015, tetapi bekerja dengan sangat baik. Ini bukan 100% dan saya harus membodohi beberapa kode - mengubah foreach menjadi for loop, menulis kelas List <T> saya sendiri, misalnya, dan Anda harus menyusun kode Anda sehingga 'murni' dengan hanya struktur data internal untuk bekerja dengan, tetapi itu adalah harga kecil yang harus dibayar karena dapat memodifikasi dan menguji kode di VS dan kemudian 'mengkompilasinya' ke Javascript melalui TypeScript.
John Mott
36

Web Essentials memungkinkan untuk mengkompilasi file C # ke .d.tsfile TypeScript saat disimpan. Kemudian Anda dapat merujuk definisi dari .tsfile Anda .

masukkan deskripsi gambar di sini

VB
sumber
Apakah Anda mungkin bingung dengan file .ts dan c #? tidak dapat menemukan opsi ini
Flores
1
Tetapi setelah beberapa pencarian saya menemukan apa yang Anda maksud .. sebenarnya cukup berguna.
Flores
2
Sebenarnya tidak, saya cukup yakin operasi 'mengkompilasi' tidak ada, itu menghasilkan kode. Itu membuat saya bingung, tetapi tidak 99% benar, saya akan memberikannya ;-)
Flores
1
Itu lebih berguna jika kita dapat mengkonfigurasi namespace dan beberapa penyesuaian.
Farshid Saberi
5
Anda sekarang harus menginstal 'TypeScript Definition Generator' secara manual untuk menggunakan ini - lihat di sini
Taran
24

TypeLite dan T4TS di atas keduanya tampak bagus, cukup pilih satu, TypeLite, buat garpu untuk mendapatkan dukungan

  • ValueTypes ,
  • Nullables
  • camelCasing (naskah akar doc menggunakan unta, dan ini berlaku terlalu baik bersama-sama dengan C #)
  • bidang publik (suka POCO yang bersih dan dapat dibaca, juga memudahkan Penyusun C #)
  • nonaktifkan pembuatan modul

Lalu aku membutuhkan C # antarmuka dan berpikir inilah saatnya untuk membuat barang saya sendiri dan menulis skrip T4 sederhana yang hanya melakukan apa yang saya butuhkan. Ini juga termasuk Enums . Tidak perlu repo, cukup <100 baris T4.

Pemakaian
Tidak ada perpustakaan, tidak ada NuGet, hanya file T4 sederhana ini - gunakan "tambahkan item" dalam Visual Studio dan pilih template T4 apa saja. Kemudian tempel ini ke dalam file. Sesuaikan setiap baris dengan "ACME" di dalamnya. Untuk setiap kelas C # tambahkan satu baris

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

Urutan penting, semua jenis yang diketahui akan digunakan dalam antarmuka follwing. Jika Anda hanya menggunakan antarmuka, ekstensi file bisa .d.ts , untuk enum Anda memerlukan file .ts , karena variabel dibuat.

Kustomisasi
Meretas skrip.

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

Tingkat skrip berikutnya adalah membuat antarmuka layanan dari kelas MVC JsonController.

citykid
sumber
1
Sangat lucu, tetapi ada typeof(ParticleKind)di dalam Enum<T>. Tentunya harus begitu typeof(T)? Anda juga perlu memperbarui boolagar menjadi booleanversi TypeScript yang lebih baru
Gone Coding
Juga perhatikan: ini putus dengan properti enum di kelas
Gone Coding
1. Uhh, ya, terima kasih atas perhatiannya, akan memperbaikinya. 2. Ketikan berkembang sejak penulisan naskah ini. Sepertinya perlu beberapa pembaruan, Anda pasti benar. Saya harap ini berfungsi sebagai titik awal untuk tujuan Anda sendiri.
citykid
1
Saya mengubahnya menjadi perpustakaan pembantu, memperbaiki bug dan sekarang hanya menggunakan entri baris tunggal di file TT saya untuk menghasilkan antarmuka dan const enums baru . Terima kasih atas contohnya. Itu sangat dekat dan memberi saya hasil kerja lebih cepat.
Gone Coding
23

Jika Anda menggunakan vscode, Anda dapat menggunakan ekstensi saya csharp2ts yang melakukan hal itu.

Anda cukup memilih kode C # yang ditempelkan dan menjalankan Convert C# to TypeScriptperintah dari palet perintah masukkan deskripsi gambar di sini Contoh konversi:

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

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

untuk

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

    /**Person name */
    Name : string;
}
Rafael
sumber
1
Saya pikir orang tertarik dengan solusi otomatis penuh di mana kompilasi dengan msbuild menghasilkan definisi skrip sebelum mengonsumsinya. Apakah ada cara untuk mendapatkannya menggunakan plugin?
binki
Tidak, ini adalah plugin VSCode, hanya bekerja di dalam editor dan bukan sebagai program yang berdiri sendiri
Rafael
Saya telah mengubah ekstensi vscode ini menjadi modul node jika Anda ingin melalui node.js atau tytpescript. Anda dapat memeriksa reponya di
Sagar Rana Magar
Apakah ada cara untuk menautkan perintah ke pintasan keyboard? Misalnya, akan memilih kode .net, dan memiliki setup shift + ctrl + c untuk menjalankan "Convert C # to TypeScript", yang akan mempercepat proses. Saya suka pluginnya!
Pawel Cioch
18

Inilah pendekatan saya untuk menyelesaikannya. Deklarasikan kelas C # Anda dengan atribut dan .d.ts-files akan dibuat (menggunakan transformasi T4). Ada paket di nuget dan sumbernya tersedia di github . Saya masih mengerjakan proyek ini, tetapi dukungannya cukup ekstensif.

Christoffer
sumber
Saya membuat fork proyek ini dan menambahkan dukungan KO di sini: github.com/omniscient/t4ts
Frank.Germain
18

Jika Anda menggunakan Visual Studio, tambahkan ekstensi Mesin Ketik.

Galeri Visual Studio

Situs web / Dokumentasi

Memperbarui

Dengan Web Essentials diinstal di VS 2015, Anda dapat mengklik kanan file kelas, lalu> Web Essentials> Buat File Intellisense Skrip Ketik dari menu konteks.

Michael Tranchida
sumber
Itu membuat file d.ts untuk dukungan intellisense tetapi bagaimana seseorang menggunakannya dan kemudian apa hubungannya dengan pembuatan kelas yang mendasarinya? Saya membuka WebEssentails dan tidak dapat menemukan dokumen apa pun. Ada saran? TIA.
howardlo
@hio Cukup rujuk file d.ts dalam file .ts apa pun yang Anda perlukan untuk menggunakannya. Saat / jika Anda mengubah kelas, file d.ts yang mendasarinya akan diperbarui. (Tip: Anda dapat menyeret dan melepaskan d.ts file ke bagian atas file .ts dan itu akan membuat referensi untuk Anda.)
Michael Tranchida
Terima kasih Michael! Saya mencoba menjatuhkan file d.ts ke file .ts kosong dan itu hanya menambahkan file ke folder yang berisi. Mencoba di VS2015 dan VS2017 baru, hasil yang sama. Apakah Anda mengetahui video atau tutorial yang menunjukkan bagaimana semua ini bekerja? TIA
howardlo
Saya mencoba menjatuhkan file d.ts ke file .ts di editor dan itu membuat referensi. Saya rasa saya mengerti sekarang. Tutorial masih disambut baik. Terima kasih!
howardlo
@hlo Maaf, tidak tahu ada tutorial. Ketika saya pergi ke rute Web Essentials, saya telah membuat file .ts duplikat karena model domain saya ada di perpustakaan kelas, dan di kode sisi klien saya, saya biasanya perlu membuat model dto atau vm, yang diperlukan browser tahu tentang. Jika Anda mengalami masalah dengan semua ini, coba ekstensi Mesin Ketik. Ini memungkinkan Anda untuk memiliki file model ur .ts di mana pun Anda inginkan.
Michael Tranchida
15

Coba kerangka kerja Reinforced.Typings. Sepertinya itu menyelesaikan masalah Anda.

  1. Instal dari NuGet
  2. Arahkan ke POCO Anda dan tambahkan [TsInterface]atribut di atasnya

    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. Bangun kembali proyek Anda
  4. Temukan kode TypeScript yang dihasilkan dalam %Your_Project_Directory%/Scripts/project.tsfile dan tambahkan ke proyek secara manual

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. Lakukan hal yang sama untuk semua POCO Anda dan referensi project.tsdi kode TypeScript Anda yang lain.

Lihat detail lebih lanjut di wiki dokumentasi

Pavel B. Novikov
sumber
Tambahkan cuplikan sampel daripada hanya membagikan URL
Venkat.R
Ada wiki dengan quickstart O_o github.com/reinforced/Reinforced.Typings/wiki
Pavel
Tapi ok, saya akan memberikan contoh di sini :)
Pavel B. Novikov
Tidak. Dukungan NET Core ( tautan ) :(
Alex Klaus
5
@AlexKlaus .NET Dukungan Inti telah tiba
Pavel B. Novikov
10

Saya telah membuat utilitas kecil yang dapat menghasilkan antarmuka TypeScript dari kelas C #. Tersedia sebagai paket NuGet . Dokumentasi terperinci dapat ditemukan di halaman web proyek .

Lukas Kabrt
sumber
Perpustakaan yang bagus, usaha yang bagus. Sayangnya tidak menemukan cara untuk mengubah tipe nilai yang dihasilkan, misalnya mengubah "string" menjadi "KnockoutObservableString" atau "string []" menjadi "KnockoutObservableArray". Apakah itu sesuatu yang ada dalam rencana masa depan?
root
2
Saya menggunakan T4TS sebagai gantinya, butuh 14 menit.
root
@root, Anda seharusnya tidak benar-benar mengonversi string [] menjadi KnockoutObservableArray dalam definisi yang dihasilkan. Anda menggunakan definisi yang dihasilkan ini saat Anda benar-benar menggunakan instance serial dari kelas-kelas ini. Sekarang, Anda mungkin menjalankan seluruh objek melalui plugin pemetaan, tetapi saya akan berhati-hati terhadap hal ini. Itu bisa berlebihan dan saya selalu lebih suka mengonversi secara manual (mungkin melalui ctor) dari contoh serial kelas C # Anda ke kelas TypeScript yang penuh dengan observable. Satu-satunya waktu yang saya sarankan untuk menjalankannya secara membabi buta melalui plugin pemetaan adalah untuk aplikasi gaya CRUD.
Allen Rice
@Lukas Kabrt, terima kasih banyak untuk TypeLite, ini sangat bermanfaat dalam proyek kami dan saya menulis tentangnya secara singkat di sini: underwatergorilladome.com/…
Allen Rice
@ AllenRice, saya merasa berguna untuk memiliki kelas model tampilan Knockout buatan tangan, di mana saya menggunakan pendekatan yang Anda jelaskan dan menggabungkannya dengan kelas yang dibuat secara otomatis yang merupakan DTO yang diteruskan melalui plugin pemetaan.
root
7

Silakan lihat di perpustakaan ini Mesin Ketik

Itu mengubah tidak hanya kelas, enum, antarmuka dll, tetapi juga pengontrol api, yang sangat mengagumkan ..

Selain itu, ia melakukannya segera setelah Anda menyimpan file .cs sumber, jadi saya tidak perlu memicu alat eksternal apa pun. Simpan .cs dan dapatkan pembaruan .ts

harishr
sumber
Hal yang hebat adalah ia menghasilkan file TS saat menyimpan file CS yang sesuai. Namun, pengaturan folder keluaran cukup rapuh (lihat pembahasan di sini ) dan membutuhkan beberapa kode buatan tangan.
Alex Klaus
Saya memang menggunakan alat pembuatan untuk itu, dan alat ini jauh lebih kuat daripada yang disebutkan di sini
harishr
6

Saya punya sedikit solusi yang menggunakan template T4 ( lihat sumber ).

Anda pergi dari CLR POCO mana saja:

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

Ke antarmuka TypeScript:

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

Anda dapat menggunakan proyek sumber terbuka NSwag : Di GUI, Anda dapat memilih kelas .NET dari DLL .NET yang ada dan membuat antarmuka TypeScript untuknya.

Proyek ini juga menyediakan alat baris perintah dan dukungan untuk templat T4 serta pembuatan kode klien untuk pengontrol API Web ...

Rico Suter
sumber
Ketahuilah, bahwa NSwag hanya akan menghasilkan file TS dari file biner (Anda juga memerlukan semua dependensi binari Anda) atau file JSON-nya, yang dihasilkan Swagger dari file biner.
Alex Klaus
3

Jika Anda perlu membuat file terpisah untuk setiap kelas / antarmuka TypeScript yang dihasilkan (yaitu dengan cara "kelas tunggal per file"), Anda dapat mencoba TypeGen . Ini adalah alat yang dapat Anda gunakan dari Package Manager Console untuk menghasilkan file TypeScript berdasarkan C # class / enums Anda. Saat ini mendukung:

  • mengekspor enum; mengekspor POCO sebagai kelas atau antarmuka TS
  • warisan
  • tipe generik
  • koleksi / jenis koleksi bersarang

ditambah beberapa fitur tambahan. Ini juga open source (Anda dapat memeriksanya di github ).

JB1
sumber
2

Bagaimana dengan sebaliknya?

Lihat erecruit TypeScript Translator . Itu datang dengan dukungan C # siap pakai, tetapi sebenarnya berbasis template (menggunakan Nunjucks untuk rendering), yang berarti dapat menghasilkan apa pun - VB.NET, F #, C ++, XML, SQL - apa pun yang dapat Anda encode dengan template.

Berfungsi sebagai program konsol .NET, program NodeJS (untuk mereka yang tidak menggunakan Windows), atau sebagai ekstensi Visual Studio , lengkap dengan fungsi buat-simpan. Dan termasuk dukungan MSBuild, hanya untuk membuat server build Anda senang. :-)

Fyodor Soikin
sumber
Saya memberi ini +1 karena ini benar-benar solusi terbaik, fitur penghasil-saat-simpan adalah fitur mematikan.
John Zabroski
2

Anda juga dapat menggunakan ini: https://github.com/pankleks/TypeScriptBuilder

Pustaka kecil ini menghasilkan definisi tipe TypeScript berdasarkan tipe C #. Gunakan secara langsung di proyek C # backend Anda untuk menghasilkan kode untuk proyek TypeScript frontend Anda. Anda juga dapat membuat aplikasi konsol kecil, untuk menghasilkan kode dengan alat pra-bangun.

Bekerja pada kerangka Full & NET Core!

Instal dengan nuget: Install-Package TypeScriptBuilder

Fitur yang didukung

  • Mengatasi ketergantungan tipe
  • Generik
  • Ketik warisan
  • Namespaces (modul)
  • Enum
  • Jenis nullable
  • Konverison kamus (ke objek indeks TS tipe kuat)
  • Set atribut kontrol pembuatan kode
  • any untuk jenis yang tidak dapat diubah

Deskripsi selengkapnya: https://github.com/pankleks/TypeScriptBuilder/blob/master/README.md

pankleks
sumber
Baru saja mencoba TypeScriptBuilderdan sejauh ini terlihat luar biasa; hore untuk dukungan .NET Core!
Tobias J
1

Guys lihat di https://github.com/reinforced/ Reinforced.Typings . Saya telah bermain-main dengan template typelite dan t4 selama beberapa hari terakhir dan berakhir dengan proyek ini. Ini sangat sederhana dan bekerja seperti pesona. Dapatkan saja paketnya, ubah file konfigurasi (seperti selama 10 detik) dan buat. Semua dilakukan secara otomatis tanpa masalah apa pun. Berkatilah penulisnya!

Hal buruk tentang template T4 adalah bahwa setelah Anda membangun dari VS, rakitan yang dipindai terkunci dan Anda harus memulai ulang VS (betapa konyolnya itu?). Ada beberapa solusi di T4 Toolbox + beberapa arahan pembersihan VS tetapi tidak ada yang berhasil untuk saya.

veb
sumber
1

Saya suka solusi citykid. Saya telah memperpanjangnya sedikit. Jadi, solusi juga didasarkan pada teknik pembuatan kode dengan template T4.

Itu dapat menghasilkan tipe TypeScript umum dan deklarasi ambient.

Ini mendukung pewarisan dan implementasi antarmuka.

Mendukung generik, array dan daftar sebagai bidang tipe.

Juga diterjemahkan ke jenis TypeScript yang tidak secara eksplisit disebutkan dalam konfigurasi (misalnya kita mengimpor tipe A, dan dalam keluaran TS Anda dapat menemukan beberapa jenis lain: jenis bidang, jenis dasar, dan antarmuka).

Anda juga dapat mengganti nama tipe.

Enum juga didukung.

Contoh penggunaan (Anda dapat menemukannya di repositori proyek):

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

Dan Anda akan mendapatkan hasil

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

Periksa solusi lengkapnya di sini: https://bitbucket.org/chandrush/cst4ts

RollingStone
sumber
1

Anda juga dapat menggunakan Bridge.net. Dari versi 1.7 itu mendukung pembuatan definisi TypeScript untuk tipe C #. Lihat http://bridge.net/docs/generate-typescript-definitions/

George Birbilis
sumber
Masalah utama adalah ketika Anda melakukan pencarian Google, Anda mungkin sampai pada pertanyaan asli dan tidak pernah menyadari bahwa info berguna ada pada jawaban duplikat / tertutup
George Birbilis
Jadi, pastikan kanonis memiliki informasi terbaik. Jangan memposting ke banyak pertanyaan. Diskusi lebih lanjut tentang ini dapat dibawa ke Meta Stack Overflow
Martijn Pieters
1

Saya juga sangat menyukai jawaban @ citykid, jadi saya memperluasnya untuk membuat seluruh namespace dalam satu waktu. Letakkan saja kelas POCO ke dalam namespace, dan buat ulang template T4. Saya berharap saya tahu bagaimana membuat file terpisah untuk masing-masing, tapi itu bukan akhir dari dunia.

Anda perlu mereferensikan file .DLL di bagian atas (di mana kelas yang Anda inginkan), dan Anda perlu menyebutkan namespace. Semua baris yang akan diedit ditandai dengan ACME. Pujian utama untuk @citykid, hargai!

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

Solusi saya adalah menulis util codegen kecil yang hanya mengambil rakitan proyek (dan merujuk rakitan) dan mulai memindai jenis yang terlibat dalam interaksi antara skrip ketikan dan c #. Ut ini mengeluarkan kedua javascript sebagai d.ts ... Alat ini dipanggil dalam acara pasca-pembuatan ... bekerja seperti pesona!

Paul0515
sumber
Saya tidak tahu mengapa saya memilih untuk mengeluarkan js dan d.ts ... sekarang ini hanya menghasilkan .ts ... lugas dan sangat bisa dilakukan.
Paul0515
1
Hai Paul ... bisakah Anda membagikan kode util dengan kami. Saya ingin membuat file ts (di lokasi folder tertentu) dan bukan file d.ts seperti yang Anda katakan. Apakah itu sesuatu yang bisa dilakukan staf Anda ??
Krishna Teja Veeramachaneni
0

Jika tertarik, Anda bisa menggunakan TypedRpc . Tujuannya tidak hanya untuk membuat antarmuka di TypeScript, tetapi untuk membuat semua komunikasi dengan layanan di .Net menggunakan protokol JsonRpc.

Contoh kelas di server:

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

Penggunaan kode TypeScript yang dihasilkan:

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

Lihat https://github.com/Rodris/TypedRpc untuk contoh lain tentang cara menggunakannya.

Rodris
sumber
0

Generator Klien API Web ASP.NET mungkin lebih berguna, lebih sedikit overhead daripada toolchain yang angkuh dan lainnya selama SDLC.

Sementara programmer umumnya menggunakan WebApiClientGen untuk menghasilkan kode API klien, proyek ini juga menyediakan POCO2TS.exe, program baris perintah yang menghasilkan antarmuka TypsScript dari kelas POCO. Anda dapat menggunakan Poco2ts.exe atau komponen poco2ts untuk mengintegrasikan pembuatan kode dengan pipeline build Anda.

ZZZ
sumber
0

Jika Anda ingin mengubahnya melalui node.js maka Anda dapat menggunakan paket ini (csharp-to-typescript). https://www.npmjs.com/package/csharp-to-typescript

kode sumber: 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
sumber
0

Jika Anda menggunakan VSCode, Anda dapat melihat ekstensi C # ke TypeScript

Ubah kelas C # ke antarmuka TypeScript

Lihat bagaimana saya bisa mengubahnya dari kode C # hanya dengan satu klik. Tentu saja, tidak semua kelas akan dikonversi seperti pabrik, tetapi cukup baik untuk sisi klien. Kami hanya membutuhkan bentuk datanya. Terkadang jika saya perlu menggunakan pola pengunjung, saya akan menghias dengan metode tambahan yang saya butuhkan. Hanya butuh 5 detik untuk melakukannya. Dibandingkan dengan satu menit di atas, saya bisa mengatakan ini adalah kemenangan besar.

Lihat lebih detail di posting blog saya

trungk18
sumber