Cách sử dụng lại các định nghĩa lớp C # hiện có trong các dự án TypeScript


121

Tôi sẽ bắt đầu sử dụng TypeScripttrong dự án khách hàng HTML của mình, dự án này thuộc dự án MVC với mô hình miền khung thực thể đã có ở đó. Tôi muốn hai dự án của mình (phía máy khách và phía máy chủ) hoàn toàn tách biệt vì hai nhóm sẽ làm việc trên này ... JSON và REST được sử dụng để giao tiếp các đối tượng qua lại.

Tất nhiên, domaincác đối tượng của tôi ở phía máy khách phải khớp với các đối tượng ở phía máy chủ. Trong quá khứ, tôi thường làm điều này theo cách thủ công. Có cách nào để sử dụng lại các định nghĩa lớp C # của tôi (đặc biệt là các POJOlớp trong mô hình miền của tôi) để tạo các lớp tương ứng trong TypeScript "không?


Không, chúng là những ngôn ngữ hoàn toàn khác nhau.
Hans Passant

6
Vâng, ý tôi là POCO. Tôi biết chúng là các ngôn ngữ hoàn toàn khác nhau ... nhưng sẽ thật tuyệt nếu bằng cách nào đó tránh nhập lại tất cả những thứ này ... Tôi nghĩ rằng hiện tại tôi sẽ sao chép và dán mã c # của mình .. và sẽ cấu trúc lại mọi thứ cho đến khi nó biên dịch xong TypeScript ... bằng cách đó tôi chắc chắn rằng tôi đã không gõ sai một thuộc tính .. và giúp tôi không cần phải nhớ. Nhưng điều này nghe có vẻ không hay chút nào.
pabloelustondo

1
Tôi cũng quan tâm đến hướng khác - từ các lớp mô hình Typecript đến các lớp mô hình C #, có thể mô tả hai chiều thông qua JSON.
Jason Kleban

Tôi đã tìm kiếm thứ tương tự và tôi vừa tình cờ tìm thấy plugin Gulp này mặc dù tôi không biết có bao nhiêu hỗ trợ cho nó
Luke T O'Brien

Câu trả lời:


54

Hiện tại không có bất kỳ thứ gì sẽ ánh xạ C # sang TypeScript. Nếu bạn có nhiều POCO hoặc bạn nghĩ chúng có thể thay đổi thường xuyên, bạn có thể tạo một công cụ chuyển đổi - một cái gì đó đơn giản dọc theo ...

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

Đến

export class MyPoco {
    public Name: string;
}

Ngoài ra còn có một cuộc thảo luận trên Codeplex về việc tự động tạo từ C # .

Chỉ để cập nhật mọi thứ, TypeLite có thể tạo giao diện TypeScript từ C #:

http://type.litesolutions.net/


Yeahp, một cái gì đó như thế này là những gì tôi đã nghĩ để làm thủ công .. tốt. Không chắc bây giờ tôi có thời gian để viết một trình chuyển đổi .. nhưng có, đó sẽ là ý tưởng. Cảm ơn. Có thể Microsoft đang làm điều đó ngay bây giờ tùy theo chúng tôi nói.
pabloelustondo

Bạn có thể thực hiện việc này bằng bất kỳ cách nào trong hai cách ... Tạo tệp .ts với sự trợ giúp của EnvDTE Automation hoặc bằng cách sử dụng Mef Directory Catalog và Reflection / Introspection. Tôi thích cái thứ hai hơn vì nó không phụ thuộc vào hình ảnh.
Arek Bal

1
Tôi đã bắt đầu sử dụng dart và gặp phải vấn đề tương tự về cách chia sẻ các loại giữa c # và javascript. Tôi hy vọng rằng vấn đề này sẽ được giải quyết bằng Typecript, nhưng có vẻ như câu trả lời là chưa. Tôi cũng là một chút hư hỏng do saltarelle-trình biên dịch mà biên soạn c # để javascript khá độc đáo saltarelle-compiler.com
BraveNewMath

2
@DanielHarvey Enums được tạo chính xác bởi TypeLite, có thể đã được sửa vì nhận xét của bạn.
pauloya

1
TypeScriptPaste sẽ chuyển đổi C # thànhTypescript. Bạn phải có trình biên dịch Roslyn, có nghĩa là Visual Studio 2015, nhưng nó hoạt động thực sự tốt. Nó không phải là 100% và tôi đã phải đọc một số mã - chuyển đổi foreach thành vòng lặp for, ví dụ như viết lớp List <T> của riêng tôi và bạn phải cấu trúc mã của mình để nó 'thuần túy' chỉ với các cấu trúc dữ liệu nội bộ để làm việc với, nhưng phải trả một cái giá nhỏ để có thể sửa đổi và kiểm tra mã trong VS và sau đó 'biên dịch' nó sang Javascript thông qua TypeScript.
John Mott

36

Web Essentials cho phép biên dịch tệp C # thành tệp TypeScript .d.tskhi lưu. Sau đó, bạn có thể tham khảo các định nghĩa từ các .tstệp của mình .

nhập mô tả hình ảnh ở đây


Bạn có thể nhầm lẫn giữa tệp .ts và c # không? không thể tìm thấy tùy chọn này
Flores

1
Nhưng sau một số tìm kiếm, tôi đã tìm thấy ý của bạn .. thực sự khá hữu ích.
Flores

2
Thực ra không phải vậy, tôi khá chắc chắn rằng thao tác 'biên dịch' không có gì, nó tạo ra mã. Đó là nhầm lẫn tôi, nhưng is't 99% đúng, tôi sẽ cung cấp cho bạn mà ;-)
Flores

1
Sẽ hữu ích hơn nếu chúng ta có thể định cấu hình không gian tên của nó và một số tùy chỉnh.
Farshid Saberi

5
Bây giờ bạn phải cài đặt 'Trình tạo Định nghĩa TypeScript' theo cách thủ công để sử dụng - xem tại đây
Taran

24

TypeLite và T4TS ở trên đều có vẻ tốt, chỉ cần chọn một cái, TypeLite, chia nhỏ nó để được hỗ trợ

  • ValueTypes ,
  • Nullables
  • camelCasing (tài liệu gốc của TypeScript sử dụng lạc đà và điều này rất tốt khi kết hợp với C #)
  • các trường công cộng (yêu thích các POCO sạch và dễ đọc, cũng giúp cho Trình biên dịch C # trở nên dễ dàng)
  • vô hiệu hóa tạo mô-đun

Sau đó, tôi cần các giao diện C # và nghĩ rằng đã đến lúc nướng thứ của riêng mình và viết một tập lệnh T4 đơn giản chỉ làm những gì tôi cần. Nó cũng bao gồm Enums . Không cần repo, chỉ cần <100 dòng T4.

Cách sử dụng
Không có thư viện, không có NuGet, chỉ cần tệp T4 đơn giản này - sử dụng "thêm mục" trong Visual Studio và chọn bất kỳ mẫu T4 nào. Sau đó, dán nó vào tệp. Điều chỉnh mọi dòng với "ACME" trong đó. Đối với mỗi lớp C #, hãy thêm một dòng

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

Vấn đề đặt hàng, bất kỳ loại nào đã biết sẽ được sử dụng trong các giao diện follwing. Nếu bạn chỉ sử dụng giao diện, phần mở rộng tệp có thể là .d.ts , đối với enums, bạn cần tệp .ts , vì một biến được khởi tạo.

Tùy chỉnh
Hack kịch bản.

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

Cấp độ tiếp theo của script sẽ là tạo giao diện dịch vụ từ lớp MVC JsonController.


1
Rất dễ thương, nhưng bạn có typeof(ParticleKind)trong của bạn Enum<T>. Chắc chắn là nên typeof(T)? Ngoài ra bạn cần phải cập nhật boolđược booleancho các phiên bản nguyên cảo sau
Cuốn Mã hóa

Cũng lưu ý: phá vỡ này có đặc tính enum trong lớp
Cuốn Mã hóa

1. Uhh, vâng, cảm ơn vì những người đứng đầu, sẽ khắc phục điều đó. 2. Typecript đã phát triển kể từ khi viết script này. Có vẻ như nó có thể cần một số cập nhật, bạn chắc chắn đúng. Tôi hy vọng nó phục vụ như một điểm khởi đầu cho mục đích của riêng bạn.
citykid

1
Tôi đã chuyển đổi nó thành một thư viện trợ giúp, sửa lỗi và bây giờ chỉ sử dụng các mục nhập một dòng trong các tệp TT của mình để tạo giao diện và các giao diện mới const enum. Cảm ơn vì ví dụ. Nó đã rất gần và giúp tôi có kết quả làm việc nhanh hơn nhiều.
Gone Coding

23

Nếu bạn sử dụng vscode, bạn có thể sử dụng csharp2ts tiện ích mở rộng của tôi , nó thực hiện chính xác điều đó.

Bạn chỉ cần chọn mã C # đã dán và chạy Convert C# to TypeScriptlệnh từ bảng lệnh nhập mô tả hình ảnh ở đây Một ví dụ chuyển đổi:

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

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

đến

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

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

1
Tôi nghĩ rằng mọi người quan tâm đến một giải pháp hoàn toàn tự động trong đó việc biên dịch với msbuild cho ra các định nghĩa kiểu chữ trước khi sử dụng chúng. Có cách nào để đạt được điều đó bằng cách sử dụng plugin không?
binki

Không, đây là một plugin VSCode, chỉ hoạt động bên trong trình chỉnh sửa và không phải là một chương trình độc lập
Rafael

Tôi đã chuyển đổi phần mở rộng vscode này thành mô-đun nút nếu bạn muốn thông qua node.js hoặc tytpescript. Bạn có thể kiểm tra repo tại đây: github.com/YuvrajSagarRana/csharp-to-typescript
Sagar Rana Magar,

Có cách nào để liên kết lệnh với phím tắt? Ví dụ: sẽ chọn mã .net và thiết lập shift + ctrl + c để thực thi "Chuyển đổi C # sang TypeScript", điều đó sẽ tăng tốc quá trình. Tôi thích plugin!
Pawel Cioch

18

Đây là cách tiếp cận của tôi để giải quyết nó. Khai báo các lớp C # của bạn với một thuộc tính và tệp .d.ts sẽ được tạo (sử dụng biến đổi T4). Có một gói trên nuget và nguồn có sẵn trên github . Tôi vẫn đang làm việc trong dự án, nhưng sự hỗ trợ khá rộng rãi.


Tôi đã tách dự án này và thêm hỗ trợ loại trực tiếp tại đây: github.com/omniscient/t4ts
Frank.Germain

18

Nếu bạn đang sử dụng Visual Studio, hãy thêm phần mở rộng Máy đánh chữ.

Thư viện Visual Studio

Trang web / Tài liệu

Cập nhật

Với Web Essentials được cài đặt trong VS 2015, bạn có thể nhấp chuột phải vào tệp lớp, sau đó bấm> Web Essentials> Tạo tệp tin Intellisense Typescript từ menu ngữ cảnh.


Nó đã tạo tệp d.ts để hỗ trợ intellisense nhưng làm thế nào để sử dụng nó và sau đó mối quan hệ với việc tạo các lớp cơ bản là gì? Tôi đã truy cập WebEssentails và không thể tìm thấy bất kỳ tài liệu nào. Bất kỳ đề xuất? TIA.
howardlo

@hio Chỉ cần tham chiếu tệp d.ts trong bất kỳ tệp .ts nào bạn cần sử dụng. Khi / nếu bạn thay đổi lớp của mình, tệp d.ts bên dưới sẽ cập nhật. (Mẹo: Bạn có thể kéo và thả tệp d.ts lên đầu tệp .ts và nó sẽ tạo tham chiếu cho bạn.)
Michael Tranchida

Cảm ơn Michael! Tôi đã thử thả tệp d.ts xuống tệp .ts trống và nó chỉ thêm tệp vào thư mục chứa. Đã thử nó trong VS2015 và VS2017 mới, kết quả tương tự. Bạn có biết bất kỳ video hoặc hướng dẫn nào cho thấy tất cả điều này hoạt động như thế nào không? TIA
howardlo

Tôi đã thử thả tệp d.ts vào tệp .ts trong trình chỉnh sửa và nó đã tạo tham chiếu. Tôi nghĩ bây giờ tôi đã hiểu. Hướng dẫn vẫn được hoan nghênh. Cảm ơn!
howardlo

@hlo Xin lỗi, không biết bất kỳ hướng dẫn nào. Khi tôi đi theo lộ trình Web Essentials, tôi đã tạo các tệp .ts trùng lặp vì các mô hình miền của tôi nằm trong thư viện lớp và trong mã phía máy khách của tôi, tôi thường cần tạo các mô hình dto hoặc vm, mà trình duyệt cần biết về. Nếu bạn gặp sự cố với tất cả những điều này, hãy thử tiện ích Máy đánh chữ. Nó cho phép bạn có các tệp mô hình .ts ur ở bất kỳ đâu bạn muốn.
Michael Tranchida,

15

Hãy thử khung Reinforced.Typings. Có vẻ như nó giải quyết được vấn đề của bạn.

  1. Cài đặt nó từ NuGet
  2. Điều hướng đến POCO của bạn và thêm [TsInterface]thuộc tính bên trên nó

    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. Xây dựng lại dự án của bạn
  4. Tìm mã TypeScript được tạo trong %Your_Project_Directory%/Scripts/project.tstệp và thêm nó vào dự án theo cách thủ công

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. Làm tương tự cho tất cả POCO của bạn và tham chiếu project.tstrong mã TypeScript khác của bạn.

Xem thêm chi tiết trong wiki tài liệu


Thêm đoạn mã mẫu chứ không phải chia sẻ chỉ URL
Venkat.R


Nhưng ok, tôi sẽ cung cấp một ví dụ ở đây :)
Pavel B. Novikov

Hỗ trợ Không NET Core ( liên kết ) :(
Alex Klaus

5
@AlexKlaus .NET Hỗ trợ Core đã đến
Pavel B. Novikov

10

Tôi đã tạo một tiện ích nhỏ có thể tạo giao diện TypeScript từ các lớp C #. Có sẵn dưới dạng gói NuGet . Tài liệu chi tiết có thể được tìm thấy trên trang web của dự án .


Thư viện đẹp, nỗ lực tốt. Rất tiếc, đã không tìm ra cách để tinh chỉnh loại giá trị được tạo, ví dụ: chuyển đổi "string" thành "KnockoutObservableString" hoặc "string []" thành "KnockoutObservableArray". Nó có phải là một cái gì đó trong kế hoạch tương lai gần?
root

2
Tôi đã sử dụng T4TS để thay thế, mất 14 phút.
root

@root, Bạn thực sự không nên chuyển đổi một chuỗi [] thành KnockoutObservableArray trong các định nghĩa đã tạo. Bạn sử dụng các định nghĩa đã tạo này khi bạn thực sự sử dụng các phiên bản tuần tự của các lớp này. Bây giờ, bạn có thể đang chạy toàn bộ đối tượng thông qua plugin ánh xạ, nhưng tôi sẽ thận trọng với điều này. Điều đó có thể là quá mức và tôi luôn muốn chuyển đổi theo cách thủ công (có thể là thông qua ctor) từ các phiên bản tuần tự của lớp C # của bạn sang các lớp TypeScript chứa đầy những thứ có thể quan sát được. Lần duy nhất tôi khuyên bạn nên chạy nó một cách mù quáng thông qua plugin lập bản đồ là dành cho một ứng dụng kiểu CRUD.
Allen Rice,

@Lukas Kabrt, cảm ơn bạn rất nhiều vì TypeLite, nó vô cùng hữu ích trong các dự án của chúng tôi và tôi đã viết ngắn gọn về nó tại đây: undergorilladome.com/…
Allen Rice,

@AllenRice, tôi thấy thật tiện lợi khi có các lớp mô hình chế độ xem Knockout được làm thủ công, đây là nơi tôi sử dụng cách tiếp cận mà bạn đã mô tả và kết hợp nó với một lớp được tạo tự động là DTO đã được chuyển qua plugin ánh xạ.
root

7

Vui lòng xem thư viện Máy đánh chữ này

Nó chuyển đổi không chỉ các lớp, enum, giao diện, v.v. mà còn cả các bộ điều khiển api, điều này thật tuyệt vời ..

Thêm vào đó, nó thực hiện điều này ngay khi bạn lưu tệp .cs nguồn, vì vậy tôi không phải kích hoạt bất kỳ công cụ bên ngoài nào. Lưu .cs và bạn sẽ được cập nhật .ts


Điều tuyệt vời là nó tạo ra các tệp TS khi lưu các tệp CS tương ứng. Tuy nhiên, việc thiết lập thư mục đầu ra khá mỏng manh (xem thảo luận tại đây ) và yêu cầu một số mã thủ công.
Alex Klaus

Tôi có sử dụng công cụ xây dựng cho rằng, và công cụ này là cách mạnh mẽ hơn hầu hết các đề cập ở đây
harishr

6

Tôi có một giải pháp nhỏ sử dụng các mẫu T4 ( xem nguồn ).

Bạn đi từ bất kỳ CLR POCO nào:

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

Đối với giao diện TypeScript:

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

3

Bạn có thể sử dụng dự án mã nguồn mở NSwag : Trong GUI, bạn có thể chọn lớp .NET từ một DLL .NET hiện có và tạo giao diện TypeScript cho nó.

Dự án cũng cung cấp các công cụ dòng lệnh và hỗ trợ cho các mẫu T4 cũng như tạo mã máy khách cho bộ điều khiển API Web ...


Xin lưu ý rằng NSwag sẽ chỉ tạo tệp TS từ các tệp nhị phân (bạn cũng cần tất cả các tệp nhị phân phụ thuộc của mình) hoặc tệp JSON của nó, mà Swagger tạo ra từ các tệp nhị phân.
Alex Klaus

3

Nếu bạn cần tạo một tệp riêng biệt cho mọi lớp / giao diện TypeScript được tạo (tức là theo cách "một lớp cho mỗi tệp"), bạn có thể thử TypeGen . Đó là một công cụ bạn có thể sử dụng từ Bảng điều khiển Trình quản lý Gói để tạo các tệp TypeScript dựa trên các lớp / enums C # của bạn. Nó hiện hỗ trợ:

  • xuất khẩu enums; xuất POCO dưới dạng các lớp hoặc giao diện TS
  • di sản
  • loại chung chung
  • bộ sưu tập / loại bộ sưu tập lồng nhau

cộng với một số tính năng bổ sung. Nó cũng là mã nguồn mở (bạn có thể kiểm tra trên github ).


2

Làm thế nào về cách khác xung quanh?

Kiểm tra Trình dịch TypeScript của ECruit . Nó đi kèm với hỗ trợ C # sẵn sàng hoạt động, nhưng thực sự dựa trên mẫu (sử dụng Nunjucks để kết xuất), có nghĩa là nó có thể tạo ra bất kỳ thứ gì khác - VB.NET, F #, C ++, XML, SQL - bất cứ thứ gì bạn có thể mã hóa bằng mẫu.

Hoạt động như một chương trình bảng điều khiển .NET, chương trình NodeJS (dành cho những người không có trên Windows) hoặc như một phần mở rộng Visual Studio , hoàn chỉnh với chức năng tạo khi lưu. Và bao gồm hỗ trợ MSBuild, chỉ để làm cho máy chủ xây dựng của bạn hài lòng. :-)


Tôi +1 điều này bởi vì nó thực sự là giải pháp tốt nhất, tạo-để-tiết kiệm là tính năng giết người.
John Zabroski

2

Bạn cũng có thể sử dụng cái này: https://github.com/pankleks/TypeScriptBuilder

Thư viện nhỏ này tạo ra định nghĩa kiểu TypeScript dựa trên các kiểu C #. Sử dụng nó trực tiếp trong dự án C # phụ trợ của bạn để tạo mã cho dự án TypeScript giao diện người dùng của bạn. Bạn cũng có thể sử dụng ứng dụng console nhỏ để tạo mã bằng các công cụ tạo sẵn.

Hoạt động trên khung Full & NET Core!

Cài đặt bởi nuget: Install-Package TypeScriptBuilder

Các tính năng được hỗ trợ

  • Giải quyết loại phụ thuộc
  • Generics
  • Nhập kế thừa
  • Không gian tên (mô-đun)
  • Enums
  • Loại vô hiệu
  • Đối chiếu từ điển (đối với các đối tượng được lập chỉ mục TS loại mạnh)
  • Tập hợp các thuộc tính điều khiển tạo mã
  • any cho các loại không thể chuyển đổi

Mô tả thêm: https://github.com/pankleks/TypeScriptBuilder/blob/master/README.md


Chỉ cần thử TypeScriptBuildervà nó trông xuất sắc cho đến nay; Hoan hô hỗ trợ .NET Core!
Tobias J

1

Các bạn xem qua https://github.com/reinforced/ Reinforced.Typings . Tôi đã chơi với các mẫu typelite và t4 trong vài ngày qua và kết thúc với dự án này. Nó siêu đơn giản và hoạt động như một sự quyến rũ. Chỉ cần lấy gói, sửa đổi tệp cấu hình (giống như trong 10 giây) và xây dựng. Tất cả được thực hiện tự động mà không có bất kỳ vấn đề nào. Chúc phúc cho tác giả!

Điều tồi tệ về các mẫu T4 là một khi bạn xây dựng từ VS, các hội đồng được quét sẽ bị khóa và bạn phải khởi động lại VS (thật ngớ ngẩn làm sao?). Có một số cách giải quyết trong Hộp công cụ T4 + một số chỉ thị làm sạch VS nhưng không có cách nào trong số này phù hợp với tôi.


1

Tôi thích giải pháp citykid. Tôi đã mở rộng nó một chút. Vì vậy, giải pháp cũng dựa trên kỹ thuật tạo mã với mẫu T4.

Nó có thể tạo ra các loại TypeScript phổ biến và khai báo môi trường xung quanh.

Nó hỗ trợ kế thừa và triển khai giao diện.

Hỗ trợ chung, mảng và danh sách dưới dạng trường kiểu.

Ngoài ra, nó dịch sang các loại TypeScript không được đề cập rõ ràng trong cấu hình (ví dụ: chúng tôi nhập loại A và trong đầu ra TS, bạn có thể tìm thấy một số loại khác: loại trường, loại cơ sở và giao diện).

Bạn cũng có thể ghi đè tên của loại.

Enums cũng được hỗ trợ.

Ví dụ về cách sử dụng (bạn có thể tìm thấy nó trong kho dự án):

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

Và bạn sẽ nhận được một đầu ra

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

Kiểm tra toàn bộ giải pháp tại đây: https://bitbucket.org/chandrush/cst4ts


1

Bạn cũng có thể sử dụng Bridge.net. Từ phiên bản 1.7, nó hỗ trợ tạo các định nghĩa TypeScript cho các loại C #. Xem http://bridge.net/docs/generate-typescript-definitions/


Vấn đề chính là khi bạn thực hiện tìm kiếm trên google, bạn có thể gặp câu hỏi ban đầu và không bao giờ nhận thấy rằng thông tin hữu ích tồn tại ở một câu trả lời trùng lặp / đã đóng
George Birbilis

Vì vậy, hãy đảm bảo trang chuẩn có thông tin tốt nhất. Không đăng nhiều câu hỏi. Bất kỳ cuộc thảo luận nào thêm về điều này có thể được đưa đến Meta Stack Overflow
Martijn Pieters

1

Tôi cũng rất thích câu trả lời của @ citykid, vì vậy tôi đã mở rộng nó để thực hiện toàn bộ không gian tên cùng một lúc. Chỉ cần đặt các lớp POCO vào không gian tên và xây dựng lại các mẫu T4. Tôi ước mình biết cách tạo các tệp riêng biệt cho từng tệp, nhưng đó không phải là ngày tận thế.

Bạn cần tham chiếu các tệp .DLL ở phần trên cùng (nơi chứa các lớp mà bạn muốn) và bạn cần đề cập đến các không gian tên. Tất cả các dòng để chỉnh sửa được đánh dấu bằng ACME. Những điều đáng mừng cho @citykid, hãy đánh giá cao nó!

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

Giải pháp của tôi là viết một đoạn mã nhỏ sử dụng chỉ đơn giản là lấy một tổ hợp dự án (và các hội đồng tham chiếu) và bắt đầu quét các kiểu có liên quan đến sự tương tác giữa các typecript và c #. Sử dụng này xuất ra cả javascript dưới dạng d.ts ... Công cụ được gọi trong sự kiện sau xây dựng ... hoạt động như một sự quyến rũ!


Tôi không biết tại sao tôi lại chọn xuất js và d.ts ... ngay bây giờ nó chỉ xuất ra .ts ... đơn giản và rất khả thi.
Paul0515

1
Xin chào Paul ... bạn có thể chia sẻ mã sử dụng với chúng tôi không. Tôi đang tìm cách chỉ tạo tệp ts (tại một vị trí thư mục nhất định) chứ không phải tệp d.ts như bạn đã nói. Đó có phải là điều mà người sử dụng của bạn có thể làm được không ??
Krishna Teja Veeramachaneni

0

Nếu quan tâm, bạn có thể sử dụng TypedRpc . Mục đích của nó không chỉ là tạo các giao diện trong TypeScript mà còn tạo ra tất cả các giao tiếp với dịch vụ trong .Net bằng giao thức JsonRpc.

Ví dụ cho một lớp trong máy chủ:

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

Cách sử dụng mã TypeScript đã tạo:

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

Hãy xem https://github.com/Rodris/TypedRpc để biết các ví dụ khác về cách sử dụng nó.


0

ASP.NET Web API Client Generator có thể tiện dụng hơn, ít chi phí hơn so với chuỗi công cụ swagger và những thứ khác trong SDLC.

Trong khi các lập trình viên thường sử dụng WebApiClientGen để tạo mã API máy khách, dự án này cũng cung cấp POCO2TS.exe, một chương trình dòng lệnh tạo giao diện TypsScript từ các lớp POCO. Bạn có thể sử dụng Poco2ts.exe hoặc thành phần poco2ts để tích hợp việc tạo mã với đường dẫn xây dựng của bạn.


0

Nếu bạn muốn chuyển đổi nó thông qua node.js thì bạn có thể sử dụng gói này (csharp-to-stylescript). https://www.npmjs.com/package/csharp-to-typescript

chua: 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

Nếu bạn đang sử dụng VSCode, bạn có thể xem phần mở rộng C # thành TypeScript

Chuyển đổi lớp C # sang giao diện TypeScript

Xem cách tôi có thể chuyển đổi nó từ mã C # chỉ bằng một cú nhấp chuột. Tất nhiên, không phải tất cả các lớp sẽ được chuyển đổi chẳng hạn như factory, nhưng nó đủ tốt cho phía máy khách. Chúng ta chỉ cần hình dạng của dữ liệu. Đôi khi Nếu tôi cần sử dụng mẫu khách, tôi sẽ trang trí bằng các phương pháp bổ sung mà tôi cần. Chỉ mất 5 giây để làm như vậy. So sánh với một phút ở trên, tôi có thể nói đó là một chiến thắng lớn.

Xem thêm chi tiết trong bài đăng trên blog của tôi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.