TypeScript projelerinde mevcut C # sınıfı tanımları nasıl yeniden kullanılır?


122

Ben sadece, TypeScriptzaten var olan bir varlık çerçeve etki alanı modeline sahip bir MVC projesine ait olan HTML istemci projemde kullanmaya başlayacağım . İki projemin (istemci tarafı ve sunucu tarafı) tamamen ayrı olmasını istiyorum, çünkü iki ekip bu konuda çalışacak ... JSON ve REST, nesneleri ileri geri iletmek için kullanılır.

Tabii ki, domainistemci tarafındaki nesnelerim sunucu tarafındaki nesnelerle eşleşmelidir. Geçmişte bunu normalde manuel olarak yaptım. POJOTypeScript "de karşılık gelen sınıfları oluşturmak için C # sınıfı tanımlarımı (özellikle etki alanı modelimdeki sınıfları) yeniden kullanmanın bir yolu var mı ?


Hayır, tamamen farklı diller.
Hans Passant

6
Evet, POCO demek istedim. Tamamen farklı diller olduğunu biliyorum ... ama bir şekilde bunları tekrar yazmaktan kaçınmak harika olur ... Şimdilik c # kodumu kopyalayıp yapıştıracağım .. ve derlenene kadar her şeyi yeniden düzenleyeceğimi düşünüyorum. TypeScript ... bu şekilde, bir özniteliği yanlış yazmadığımdan eminim .. ve hatırlamama gerek kalmadan bana yardım eder. Ancak bu açıkça kulağa hiç hoş gelmiyor.
pabloelustondo

1
Diğer yönle de ilgileniyorum - Typescript model sınıflarından C # model sınıflarına, JSON ile çift yönlü olarak serileştirilebilir hale getirilebilir.
Jason Kleban

Ben de aynısını arıyordum ve bu Gulp eklentisine tökezledim, ancak bunun için ne kadar destek olduğunu bilmiyorum
Luke T O'Brien

Yanıtlar:


54

Şu anda C # 'ı TypeScript ile eşleştirecek hiçbir şey yok. Çok sayıda POCO'nuz varsa veya bunların sık sık değişebileceğini düşünüyorsanız, bir dönüştürücü yaratabilirsiniz - basit bir şey ...

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

için

export class MyPoco {
    public Name: string;
}

C # 'dan otomatik oluşturma hakkında Codeplex hakkında bir tartışma da var .

TypeLite, işleri güncel tutmak için C # 'dan TypeScript arayüzleri oluşturabilir:

http://type.litesolutions.net/


Evet, böyle bir şey manuel olarak yapmayı düşündüğüm şeydi .. güzel. Şu anda dönüştürücü yazmak için vaktim olduğundan emin değilim .. ama evet, fikir bu olabilir. Teşekkürler. Belki Microsoft şu anda biz konuşurken bunu yapıyor olabilir.
pabloelustondo

Bunu iki yoldan biriyle yapabilirsiniz ... EnvDTE Otomasyonu yardımıyla veya Mef Dizin Kataloğu ve Yansıma / Gözlem kullanarak .ts dosyaları oluşturun. Görsele bağlı olmadığı için ikincisini tercih ediyorum.
Arek Bal

1
Dart kullanmaya başladım ve türleri c # ve javascript arasında nasıl paylaşacağıma dair aynı sorunla karşılaştım. Bu sorunun Typescript ile çözüleceğini umuyordum, ancak cevap henüz gelmemiş gibi görünüyor. Ayrıca, c # 'ı javascript'e oldukça güzel bir şekilde derleyen saltarelle
BraveNewMath

2
@DanielHarvey Enumlar TypeLite tarafından doğru şekilde oluşturulur, muhtemelen yorumunuzdan sonra düzeltilmiştir.
pauloya

1
TypeScriptPaste, C # 'yıTypecript'e dönüştürecektir. Roslyn derleyicisine sahip olmanız gerekir, bu da Visual Studio 2015 anlamına gelir, ancak gerçekten iyi çalışıyor. Bu% 100 değil ve bazı kodları basitleştirmek zorunda kaldım - örneğin foreach'i for döngülerine dönüştürmek, kendi List <T> sınıfımı yazmak ve kodunuzu yalnızca dahili veri yapılarıyla 'saf' olacak şekilde yapılandırmalısınız. ile çalışmak, ancak VS'de kodu değiştirip test edebilmek ve ardından onu TypeScript aracılığıyla Javascript'e 'derleyebilmek' için ödenmesi gereken küçük bir bedeldi.
John Mott

37

Web Essentials , kayıt sırasında C # dosyalarını TypeScript .d.tsdosyalarına derlemeye izin verir . Daha sonra .tsdosyalarınızdan tanımlara başvurabilirsiniz.

görüntü açıklamasını buraya girin


.Ts dosyaları ve c # 'ı karıştırıyor musunuz? bu seçeneği bulamıyor
Flores

1
Ama biraz araştırdıktan sonra ne demek istediğini buldum .. aslında oldukça kullanışlı.
Flores

2
Aslında öyle değil, eminim ki işlem hiçbir şey 'derlemez', kod üretir. Bu kafamı karıştırdı, ama% 99 doğru değil, sana bunu vereceğim ;-)
Flores

1
Ad alanını ve bazı özelleştirmeleri yapılandırabilirsek daha kullanışlıydı.
Farshid Saberi

5
Şimdi bunu kullanmak için manuel olarak 'TypeScript Definition Generator' kurmanız gerekiyor
Taran

25

TypeLite ve T4TS'lerin her ikisi de iyi görünüyordu, sadece birini seçti, TypeLite, destek almak için çatalladı

  • ValueTypes ,
  • Nullables
  • camelCasing (typescript kök doc develer kullanır ve bu C # ile çok güzel buluşmanızı gider)
  • ortak alanlar (temiz ve okunabilir POCO'ları sever, ayrıca C # Derleyicisini kolaylaştırır)
  • modül oluşturmayı devre dışı bırak

Sonra C # arayüzlerine ihtiyacım vardı ve kendi işimi yapma zamanının geldiğini düşündüm ve ihtiyacım olanı yapan basit bir T4 betiği yazdım. Ayrıca Enums içerir . Depoya gerek yok, sadece <100 satır T4.

Kullanım
Kitaplık yok, NuGet yok, yalnızca bu basit T4 dosyası - Visual Studio'da "öğe ekle" yi kullanın ve herhangi bir T4 şablonunu seçin. Ardından bunu dosyaya yapıştırın. Her satırı içinde "ACME" ile uyarlayın. Her C # sınıfı için bir satır ekleyin

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

Sırayla önemli, bilinen herhangi bir tür aşağıdaki arayüzlerde kullanılacaktır. Yalnızca arabirimler kullanıyorsanız, dosya uzantısı .d.ts olabilir, numaralandırmalar için bir .ts dosyasına ihtiyacınız vardır , çünkü bir değişken başlatılır.

Özelleştirme
Komut dosyasını hackleyin.

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

Komut dosyasının bir sonraki seviyesi, MVC JsonController sınıfından servis arayüzünü oluşturmak olacaktır.


1
Çok şirin, ama typeof(ParticleKind)içinde var Enum<T>. Elbette bu olmalı typeof(T)? Ayrıca güncelleme gerekir boololmaya booleansonraki typescript sürümleri için
Kodlama Gone

Ayrıca not: bu, sınıflardaki enum özelliklerinde kesintiye neden olur
Gone Coding

1. Uhh, evet, uyarılar için teşekkür ederim, düzeltecek. 2. TypScript, bu komut dosyasını yazdığından beri gelişti. Görünüşe göre biraz güncellemeye ihtiyacı var, kesinlikle haklısın. Umarım kendi amacınız için bir başlangıç ​​noktası olarak hizmet eder.
citykid

1
Onu bir yardımcı kitaplığa dönüştürdüm, hataları düzelttim ve şimdi arayüzler ve yeni dosyalar oluşturmak için TT dosyalarımda sadece tek satırlık girişler kullanıyorum const enum. Örnek için teşekkürler. Çok yakındı ve bana çok daha hızlı bir çalışma sonucu sağladı.
Kodlama Gone

25

Vscode kullanıyorsanız , tam olarak bunu yapan csharp2ts uzantımı kullanabilirsiniz .

Yapıştırılan C # kodunu seçmeniz ve Convert C# to TypeScriptkomut paletinden komutu çalıştırmanız yeterlidir. görüntü açıklamasını buraya girin Bir dönüştürme örneği:

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

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

için

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

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

1
Bence insanlar, msbuild ile derlemenin kullanılmadan önce typcript tanımlarının çıktılarını verdiği tam otomatik bir çözümle ilgileniyor. Eklentiyi kullanarak bunu elde etmenin bir yolu var mı?
binki

Hayır, bu bir VSCode eklentisi, yalnızca düzenleyicinin içinde çalışır ve bağımsız bir program olarak çalışmaz
Rafael

Node.js veya tytpescript üzerinden isterseniz bu vscode uzantısını düğüm modülüne dönüştürdüm. Depoyu
Sagar Rana Magar

Komutu klavye kısayoluna bağlamanın bir yolu var mı? Örneğin, .net kodunu seçer ve "C # 'yi TypeScript’e Dönüştür" işlevini yürütmek için shift + ctrl + c ayarına sahip olmak işlemi hızlandırır. Eklentiyi beğendim!
Pawel Cioch

19

Visual Studio kullanıyorsanız, Typewriter uzantısını ekleyin.

Visual Studio Galerisi

Web sitesi / Belgeler

Güncelleme

VS 2015'te yüklenen Web Essentials ile , sınıf dosyasını sağ tıklayıp, ardından bağlam menüsünden> Web Essentials> TypeScript Intellisense Dosyası Oluştur'u tıklayabilirsiniz.


Intellisense desteği için d.ts dosyasını oluşturdu, ancak biri onu nasıl kullanıyor ve sonra temel sınıfları oluşturmayla ilişkisi nedir? WebEssentails'e gittim ve herhangi bir doküman bulamıyorum. Baska öneri? TIA.
howardlo

@hio Kullanmanız gereken .ts dosyasındaki d.ts dosyasına referans verin. Sınıfınızı değiştirdiğinizde / değiştirdiğinizde, temeldeki d.ts dosyası güncellenir. (İpucu: d.ts dosyasını sürükleyip bırakabilirsiniz. ts dosyasının üstüne yerleştirin ve sizin için referans oluşturacaktır.)
Michael Tranchida

Teşekkürler Michael! D.ts dosyasını boş bir .ts dosyasına bırakmayı denedim ve yalnızca dosyayı içeren klasöre ekledi. VS2015 ve yeni VS2017'de denedim, aynı sonuçlar. Tüm bunların nasıl çalıştığını gösteren herhangi bir video veya öğretici biliyor musunuz? TIA
howardlo

D.ts dosyasını düzenleyicide bir .ts dosyasına bırakmayı denedim ve referansı oluşturdu. Sanırım şimdi anlıyorum. Eğitim yine de memnuniyetle karşılandı. Teşekkürler!
howardlo

@hlo Üzgünüm, herhangi bir öğretici bilmiyorum. Web Essentials yoluna gittiğimde, alan modellerim bir sınıf kitaplığında olduğu için yinelenen .ts dosyaları oluşturuyorum ve istemci tarafı kodumda genellikle tarayıcının ihtiyaç duyduğu dto veya vm modellerini oluşturmam gerekiyor hakkında bilgi. Tüm bunlarla ilgili sorun yaşıyorsanız, Daktilo uzantısını deneyin. İstediğiniz yerde ur .ts model dosyalarına sahip olmanızı sağlar.
Michael Tranchida


15

Reinforced.Typings çerçevesini deneyin. Sorununuzu çözüyor gibi görünüyor.

  1. NuGet'ten yükleyin
  2. POCO'nuza gidin ve [TsInterface]üstüne nitelik ekleyin

    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. Projenizi yeniden oluşturun
  4. Oluşturulan TypeScript kodunu %Your_Project_Directory%/Scripts/project.tsdosyada bulun ve manuel olarak projeye ekleyin

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. Tüm POCO'larınız için aynısını yapın ve project.tsdiğer TypeScript kodunuzdaki referans .

Belgeler wiki'sinde daha fazla ayrıntı görün


Yalnızca URL'yi paylaşmak yerine örnek pasajı ekleyin
Venkat.R


Ama tamam, burada bir örnek vereceğim :)
Pavel B. Novikov

.NET Core desteği yok ( bağlantı ) :(
Alex Klaus

6
@AlexKlaus .NET Core desteği geldi
Pavel B. Novikov

10

C # sınıflarından TypeScript arabirimleri oluşturabilen küçük bir yardımcı program oluşturdum. NuGet paketi olarak mevcuttur . Ayrıntılı dokümantasyon proje web sayfasında bulunabilir .


Güzel kütüphane, iyi çaba. Maalesef üretilen değer türünü değiştirmenin bir yolunu bulamadı, örneğin "string" i "KnockoutObservableString" e veya "string []" yi "KnockoutObservableArray" e dönüştürmek. Yakın gelecek planlarında olan bir şey mi?
kök

2
Onun yerine T4TS kullandım, 14 dakika sürdü.
kök

@root, oluşturulan tanımlarda bir [] dizesini KnockoutObservableArray'e dönüştürmemelisiniz. Oluşturulan bu tanımları, bu sınıfların serileştirilmiş örneklerini gerçekten kullandığınızda kullanırsınız. Şimdi, tüm nesneyi eşleme eklentisi üzerinden çalıştırıyor olabilirsiniz, ancak buna karşı uyarıyorum. Bu aşırı olabilir ve her zaman C # sınıflarının serileştirilmiş örneklerinden gözlemlenebilirlerle dolu TypeScript sınıflarına manuel olarak (muhtemelen bir ctor aracılığıyla) dönüştürmeyi tercih ederim . Haritalama eklentisi aracılığıyla kör edici bir şekilde çalıştırmayı önerdiğim tek zaman, CRUD tarzı bir uygulama içindir.
Allen Rice

: @Lukas Kabrt, bizim projelerde son derece yararlı olmuştur ve kısaca burada bu konuda yazmış, TypeLite için çok teşekkür ederim underwatergorilladome.com/...
Allen Rice

@AllenRice, el yapımı Knockout görünüm modeli sınıflarına sahip olmayı kullanışlı buldum, bu sizin tanımladığınız yaklaşımı kullandığım ve onu, eşleme eklentisinden geçen bir DTO olan otomatik oluşturulmuş bir sınıfla birleştirdiğim yer.
kök

7

Lütfen bu kütüphaneye bir göz atın Daktilo

Yalnızca sınıfları, numaralandırmaları, arabirimleri vb. Dönüştürmez, aynı zamanda api denetleyicilerini de dönüştürür, bu da harika bir şeydir.

Ayrıca, siz kaynak .cs dosyasını kaydeder kaydetmez bunu yapar, böylece herhangi bir harici aracı tetiklememe gerek kalmaz. .Cs kaydedin ve .ts güncellemesini alın


Harika olan şey, ilgili CS dosyalarını kaydederken TS dosyalarını üretmesidir. Ancak, çıktı klasörünün ayarlanması oldukça kırılgandır ( buradaki tartışmaya bakın ) ve bazı el yapımı kodlar gerektirir.
Alex Klaus

Bunun için derleme araçları kullanıyorum ve bu araç burada en çok bahsedilenden çok daha güçlü
harishr

6

T4 şablonlarını kullanan küçük bir çözümüm var ( kaynağı görüntüle ).

Herhangi bir CLR POCO'dan gidersiniz:

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

TypeScript arayüzüne:

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

3

Açık kaynaklı NSwag projesini kullanabilirsiniz : GUI'de, mevcut bir .NET DLL'den .NET sınıfını seçebilir ve bunun için TypeScript arabirimini oluşturabilirsiniz.

Proje ayrıca T4 şablonları için komut satırı araçları ve desteğinin yanı sıra Web API denetleyicileri için istemci kodunun oluşturulmasını sağlar ...


NSwag'in TS dosyalarını yalnızca ikili dosyalardan (ikili dosyalarınızın tüm bağımlılıklarına da ihtiyacınız vardır) veya Swagger'ın ikili dosyalardan ürettiği JSON dosyasından oluşturacağını unutmayın.
Alex Klaus

3

Üretilen her TypeScript sınıfı / arabirimi için ayrı bir dosya oluşturmanız gerekiyorsa (yani, "dosya başına tek bir sınıf" biçiminde), TypeGen'i deneyebilirsiniz . C # sınıflarınıza / numaralarınıza dayalı olarak TypeScript dosyaları oluşturmak için Paket Yöneticisi Konsolundan kullanabileceğiniz bir araçtır. Şu anda şunları desteklemektedir:

  • numaralandırmaları dışa aktarma; POCO'ları TS sınıfları veya arayüzleri olarak dışa aktarma
  • miras
  • genel türler
  • koleksiyon / iç içe geçmiş koleksiyon türleri

artı bazı ek özellikler. Aynı zamanda açık kaynaklıdır ( github'da kontrol edebilirsiniz ).


2

Peki ya tam tersi?

Erecruit TypeScript Translator'a göz atın . Kullanıma hazır C # desteği ile birlikte gelir, ancak aslında şablon tabanlıdır (oluşturma için Nunjucks kullanır), bu da başka her şeyi oluşturabileceği anlamına gelir - VB.NET, F #, C ++, XML, SQL - bir şablonla kodlayabileceğiniz her şeyi.

Bir .NET konsol programı, NodeJS programı (Windows'ta olmayanlar için) veya bir Visual Studio uzantısı olarak çalışır , kaydetme üzerine oluştur işleviyle tamamlanır. Ayrıca, derleme sunucunuzu mutlu etmek için MSBuild desteği içerir. :-)


Bunu + 1'ledim çünkü gerçekten en iyi çözüm, kurtarmaya dayalı üretme katil özellik.
John Zabroski

2

Bunu da kullanabilirsiniz: https://github.com/pankleks/TypeScriptBuilder

Bu küçük kitaplık, C # türlerine göre TypeScript türü tanımı oluşturur. Ön uç TypeScript projeniz için kod oluşturmak üzere doğrudan arka uç C # projenizde kullanın. Önceden oluşturulmuş araçlarla kod oluşturmak için küçük konsol uygulaması da yazabilirsiniz.

Full & NET Core çerçevesi üzerinde çalışır!

NuGet tarafından yükleyin: Install-Package TypeScriptBuilder

Desteklenen özellikler

  • Tür bağımlılığını çözme
  • Jenerik
  • Tür mirası
  • Ad alanları (modüller)
  • Sıralamalar
  • Null yapılabilir türler
  • Sözlük yakınsaması (güçlü tip TS dizinli nesnelere)
  • Kod oluşturma kontrol öznitelikleri kümesi
  • any dönüştürülemeyen türler için

Daha fazla açıklama: https://github.com/pankleks/TypeScriptBuilder/blob/master/README.md


Sadece denedim TypeScriptBuilderve şu ana kadar mükemmel görünüyor; .NET Core desteği için yaşasın!
Tobias J

1

Çocuklar https://github.com/reinforced/ Reinforced.Typings'e bir göz attılar . Son birkaç gündür typelite ve t4 şablonlarıyla oynuyorum ve bu projeyle son buldum. Çok basit ve bir cazibe gibi çalışıyor. Sadece paketi alın, yapılandırma dosyasını değiştirin (10 saniye gibi) ve oluşturun. Hepsi herhangi bir sorun olmadan otomatik olarak yapılır. Yazarı korusun!

T4 şablonlarıyla ilgili kötü olan şey, VS'den derlediğinizde taranan derlemelerin kilitlenmesi ve VS'yi yeniden başlatmanız gerektiğidir (bu ne kadar aptalca?). T4 Toolbox + bazı VS temizleme direktiflerinde bazı geçici çözümler var, ancak bunların hiçbiri benim için işe yaramadı.


1

Citykid çözümünü beğendim. Biraz uzatmıştım. Bu nedenle çözüm, T4 şablonlarıyla kod oluşturma tekniğine de dayanmaktadır.

Yaygın TypeScript türleri ve ortam bildirimleri oluşturabilir.

Devralma ve arayüz uygulamalarını destekler.

Tür alanları olarak jenerikleri, dizileri ve listeleri destekler.

Ayrıca, konfigürasyonda açıkça belirtilmeyen TypeScript türlerini de çevirir (örneğin, A tipini içe aktarırız ve TS çıktısında başka türler de bulabilirsiniz: alan türleri, temel türler ve arabirimler).

Ayrıca türün adını geçersiz kılabilirsiniz.

Numaralandırmalar da desteklenmektedir.

Kullanım örneği (bunu proje havuzunda bulabilirsiniz):

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

Ve bir çıktı alacaksın

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

Tam çözümü buradan kontrol edin: https://bitbucket.org/chandrush/cst4ts


1

Bridge.net'i de kullanabilirsiniz. 1.7 sürümünden itibaren C # türleri için TypeScript tanımlarının oluşturulmasını destekler. Bkz. Http://bridge.net/docs/generate-typescript-definitions/


Asıl sorun, Google araması yaptığınızda, orijinal soruya gelebilir ve yinelenen / kapalı bir yanıtta yararlı bilgilerin bulunduğunu asla fark
etmeyebilirsiniz

Bu nedenle, kurallı sayfanın en iyi bilgiye sahip olduğundan emin olun. Birden fazla soruya göndermeyin. Bununla ilgili daha fazla tartışma için Meta Stack Overflow
Martijn Pieters

1

@ Citykid'in cevabını da çok beğendim, bu yüzden her seferinde bütün bir isim alanını kapsayacak şekilde genişlettim. Sadece POCO sınıflarını ad alanına yerleştirin ve T4 şablonlarını yeniden oluşturun. Keşke her biri için ayrı dosyaların nasıl oluşturulacağını bilseydim, ama bu dünyanın sonu değil.

Üst kısımdaki (istediğiniz sınıfların bulunduğu) .DLL dosyalarına başvurmanız ve ad alanlarından bahsetmeniz gerekir. Düzenlenecek tüm satırlar ACME ile işaretlenmiştir. @Citykid'e büyük tatlılar, takdir et!

<#@ 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

Benim çözümüm, basitçe bir proje derlemesini alan (ve derlemeleri başvuran) küçük bir kod oluşturucu kullanımı yazmak ve typcript ve c # arasındaki etkileşimde yer alan türleri taramaya başlamaktı. Bu kullanım, hem javascript'i d.ts olarak çıkarır ... Araç, inşa sonrası olayında çağrılır ... bir cazibe gibi çalışır!


Neden js ve d.ts çıktısını seçtiğimi bilmiyorum ... şu anda sadece .ts çıktısı veriyor ... basit ve çok yapılabilir.
Paul0515

1
Merhaba Paul ... Kullanım kodunu bizimle paylaşabilir misiniz? Söylediğiniz gibi bir d.ts dosyası değil, sadece bir ts dosyası (belirli bir klasör konumunda) oluşturmak istiyorum. Bu, kullanımınızın yapabileceği bir şey mi?
Krishna Teja Veeramachaneni

0

İlgileniyorsanız, TypedRpc'yi kullanabilirsiniz . Amacı, arabirimleri yalnızca TypeScript'te oluşturmak değil, JsonRpc protokolünü kullanarak .Net'te hizmetle tüm iletişimi oluşturmaktır.

Sunucudaki bir sınıf için örnek:

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

Üretilen TypeScript kodunun kullanımı:

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

Check out https://github.com/Rodris/TypedRpc nasıl kullanılacağını diğer örnekler için.


0

ASP.NET Web API İstemci Oluşturucuları , SDLC sırasında havalı araç zincirinden ve diğerlerinden daha kullanışlı, daha az ek yük olabilir.

Programcılar genellikle istemci API kodları oluşturmak için WebApiClientGen'i kullanırken, bu proje aynı zamanda POCO sınıflarından TypsScript arayüzleri oluşturan bir komut satırı programı olan POCO2TS.exe'yi de sağlar. Kod oluşturmayı derleme ardışık düzeninizle tümleştirmek için Poco2ts.exe veya poco2ts bileşenini kullanabilirsiniz.


0

Bunu node.js aracılığıyla dönüştürmek istiyorsanız, bu paketi kullanabilirsiniz (csharp-to-typescript). https://www.npmjs.com/package/csharp-to-typescript

kaynak kodu: 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

VSCode kullanıyorsanız, o uzantı C # ile TypeScript'e bir göz atabilirsiniz.

C # sınıfını TypeScript arayüzüne dönüştür

Sadece bir tıklamayla onu C # kodundan nasıl dönüştürebileceğimi görün. Tabii ki, fabrika gibi tüm sınıflar dönüştürülmeyecek, ancak müşteri tarafı için yeterince iyi. Sadece verilerin şekline ihtiyacımız var. Bazen ziyaretçi kalıbını kullanmam gerekirse, ihtiyacım olan ek yöntemlerle dekorasyon yapacağım. Bunu yapmak sadece 5 saniye sürdü. Yukarıdaki bir dakika ile karşılaştırıldığında, bunun büyük bir kazanç olduğunu söyleyebilirim.

Blog gönderimde daha fazla ayrıntı görün

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.