如何在TypeScript项目中重用现有的C#类定义

pab*_*ndo 111 javascript typescript

我将开始TypeScript在我的HTML客户端项目中使用,该项目属于具有实体框架域模型的MVC项目.我希望我的两个项目(客户端和服务器端)完全分离,因为两个团队将在此工作...... JSON和REST用于来回传递对象.

当然,我domain在客户端的对象应该与服务器端的对象匹配.在过去,我通常手动完成此操作.有没有办法重用我的C#类定义(特别是POJO我的域模型中的类)来在TypeScript中创建相应的类"?

Fen*_*ton 53

目前没有任何将C#映射到TypeScript的东西.如果您有很多POCO或者您认为它们可能经常更换,您可以创建一个转换器 - 简单的......

public class MyPoco {
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

export class MyPoco {
    public Name: string;
}
Run Code Online (Sandbox Code Playgroud)

讨论了Codeplex关于从C#自动生成的问题.

只是为了保持更新,TypeLite可以从C#生成TypeScript接口:

http://type.litesolutions.net/

  • @DanielHarvey枚举由TypeLite正确生成,可能自您的评论以来已修复. (2认同)

V.B*_*.B. 34

Web Essentials允许.d.ts在保存时将C#文件编译为TypeScript 文件.然后,您可以引用.ts文件中的定义.

在此输入图像描述

  • 您现在必须手动安装'TypeScript Definition Generator'才能使用它 - 请参阅[此处](/sf/answers/3164199741/) (3认同)
  • 实际上它不是,我很确定操作'编译'什么都没有,它生成代码.这让我感到困惑,但是99%是正确的,我会给你那个;-) (2认同)

cit*_*kid 22

上面的TypeLite和T4TS看起来都很好,只选了一个,TypeLite,分叉它以获得支持

  • ValueTypes,
  • Nullables
  • camelCasing(TypeScript根文档使用骆驼,这与C#一起太好了)
  • 公共领域(爱干净和可读的POCO,也使C#编译器变得容易)
  • 禁用模块生成

然后我需要C#接口,并认为是时候烘焙我自己的东西并写了一个简单的T4脚本,只是做我需要的.它还包括Enums.不需要回购,只需<100行T4.

用法
没有库,没有NuGet,只是这个简单的简单T4文件 - 在Visual Studio中使用"添加项目"并选择任何T4模板.然后将其粘贴到文件中.使用"ACME"调整每一行.为每个C#类添加一行

<#= Interface<Acme.Duck>() #>
Run Code Online (Sandbox Code Playgroud)

订单很重要,任何已知的类型都将用于以下接口.如果仅使用接口,则文件扩展名可以是.d.ts,对于需要.ts文件的枚举,因为变量是实例化的.

自定义
破解脚本.

<#@ 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();
    }
#>
Run Code Online (Sandbox Code Playgroud)

该脚本的下一级将是从MVC JsonController类创建服务接口.


Chr*_*fer 18

这是我解决它的方法.使用属性声明您的C#类,并生成.d.ts文件(使用T4转换).nuget上有一个,github 上有源代码.我还在研究这个项目,但支持非常广泛.


Mic*_*ida 17

如果您使用的是Visual Studio,请添加Typewriter扩展.

Visual Studio库

网站/文档

更新

随着网络要点安装在VS 2015年,您可以右键单击类文件,然后>网络要点>创建从上下文菜单中打字稿智能感知文件.


Raf*_*ael 17

如果你使用vscode,你可以使用我的扩展名csharp2ts.

您只需选择粘贴的C#代码并Convert C# to TypeScript从命令面板中运行命令 在此输入图像描述 转换示例:

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

    /// <summary>
    /// Person name
    /// </summary>
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

    /**Person name */
    Name : string;
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为人们对完全自动化的解决方案感兴趣,其中使用 msbuild 编译会在使用打字稿定义之前输出它们。有没有办法使用插件来获得它? (3认同)

Pav*_*kov 13

试试Reinforced.Typings框架.似乎它解决了你的问题.

  1. NuGet安装它
  2. 导航到您的POCO并[TsInterface]在其上方添加属性

    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; }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 重建您的项目
  4. %Your_Project_Directory%/Scripts/project.ts文件中找出生成的TypeScript代码,并手动将其添加到项目中

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 对所有POCO执行相同操作并project.ts在其他TypeScript代码中引用.

文档维基中查看更多详细信息

  • @AlexKlaus .NET核心支持已经到来 (5认同)

Luk*_*brt 10

我创建了一个小实用程序,可以从C#类生成TypeScript接口.可作为NuGet包使用.详细的文档可以在项目网页上找到.

  • 我使用的是T4TS,花了14分钟. (2认同)

har*_*shr 7

请看这个图书馆打字机

它不仅可以转换类,枚举,接口等,还可以转换api控制器,这简直太棒了..

另外,只要您保存源.cs文件,它就会这样做,因此我不必触发任何外部工具.保存.cs,你得到更新.ts


dia*_*lic 5

我有一个使用T4模板的小解决方案(查看源代码).

你去任何CLR POCO:

public class Parent : Person
{
    public string Name { get; set; }
    public bool? IsGoodParent { get; set; }
    public virtual ICollection<Child> Children { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

到TypeScript接口:

///<reference path="Child.d.ts" />
///<reference path="Person.d.ts" />
interface Parent extends Person {
    Name : string;
    IsGoodParent? : bool;
    Children : Child[];
}
Run Code Online (Sandbox Code Playgroud)


小智 5

如果您需要为每个生成的 TypeScript 类/接口创建一个单独的文件(即以“每个文件一个类”的方式),您可以尝试TypeGen。您可以从包管理器控制台使用它来根据 C# 类/枚举生成 TypeScript 文件。目前它支持:

  • 导出枚举;将 POCO 导出为 TS 类或接口
  • 遗产
  • 泛型类型
  • 集合/嵌套集合类型

加上一些附加功能。它也是开源的(你可以在github上查看)。