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

IT技术 javascript typescript
2021-02-20 03:45:55

我将开始TypeScript在我的 HTML 客户端项目中使用,该项目属于一个 MVC 项目,其中已经存在实体框架域模型。我希望我的两个项目(客户端和服务器端)完全分开,因为两个团队将致力于此……JSON 和 REST 用于来回通信对象。

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

6个回答

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

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

export class MyPoco {
    public Name: string;
}

在 Codeplex 上还有一个关于从 C# 自动生成讨论

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

http://type.litesolutions.net/

@DanielHarvey 枚举由 TypeLite 正确生成,可能在您发表评论后已修复。
2021-04-25 03:45:55
是的,像这样的事情就是我想手动做的……很好。不确定我现在有时间写一个转换器……但是,是的,这就是这个想法。谢谢。可能是我们说话时微软正在做这件事。
2021-04-26 03:45:55
TypeScriptPaste 会将 C# 转换为 Typescript。你必须有 Roslyn 编译器,这意味着 Visual Studio 2015,但它运行得非常好。它不是 100%,我不得不简化一些代码——例如,将 foreach 转换为 for 循环,编写我自己的 List<T> 类,并且你必须构建你的代码,使其“纯”,只有内部数据结构可以使用,但是能够在 VS 中修改和测试代码,然后通过 TypeScript 将其“编译”为 Javascript,这是一个很小的代价。
2021-05-04 03:45:55
我开始使用 dart 并遇到了如何在 c# 和 javascript 之间共享类型的相同问题。我希望这个问题能被 Typescript 解决,但看起来答案还没有。我也被 saltarelle-compiler 宠坏了,它把 c# 编译成 javascript 相当不错saltarelle-compiler.com
2021-05-10 03:45:55
您可以通过以下两种方式中的任何一种来执行此操作...在 EnvDTE 自动化的帮助下或使用 Mef 目录目录和反射/内省生成 .ts 文件。我更喜欢第二个,因为它不依赖于视觉。
2021-05-11 03:45:55

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

在此处输入图片说明

但经过一番搜索,我发现你的意思..实际上非常有用。
2021-04-26 03:45:55
您现在必须手动安装“TypeScript Definition Generator”才能使用它 - 请参见此处
2021-04-26 03:45:55
如果我们可以配置它的命名空间和一些自定义,那就更有用了。
2021-04-30 03:45:55
实际上不是,我很确定该操作不会“编译”任何内容,它会生成代码。这让我很困惑,但不是 99% 正确,我会告诉你的 ;-)
2021-05-03 03:45:55
你可能会混淆 .ts 文件和 c# 吗?找不到这个选项
2021-05-13 03:45:55

如果您使用 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; }
}

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

    /**Person name */
    Name : string;
}
不,这是一个 VSCode 插件,只能在编辑器中工作,不能作为独立程序使用
2021-04-18 03:45:55
我认为人们对完全自动化的解决方案感兴趣,在该解决方案中,使用 msbuild 进行编译会在使用它们之前输出typescript定义。有没有办法使用插件获得它?
2021-04-22 03:45:55
如果你想通过 node.js 或 tytpescript,我已经将这个 vscode 扩展转换为 node module。你可以在这里查看 repo:github.com/YuvrajSagarRana/csharp-to-typescript
2021-05-03 03:45:55
有没有办法将命令链接到键盘快捷键?例如,将选择 .net 代码,并设置 shift+ctrl+c 以执行“将 C# 转换为 TypeScript”,这将加快进程。我喜欢这个插件!
2021-05-12 03:45:55

上面的 TypeLite 和 T4TSs 看起来都不错,就挑了一个,TypeLite,fork 得到支持

  • 值类型
  • 可空值
  • camelCasing(TypeScript 根文档使用骆驼,这与 C# 搭配得很好)
  • 公共字段(喜欢干净可读的 POCO,也让 C# 编译器更容易)
  • 禁用module生成

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

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

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

顺序很重要,任何已知类型都将用于以下接口。如果你只使用接口,文件扩展名可以是.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();
    }
#>

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

我将它转换成一个帮助程序库,修复了错误,现在在我的 TT 文件中只使用单行条目来生成接口和新的const enums。谢谢你的例子。它非常接近并且让我更快地获得工作结果。
2021-04-17 03:45:55
1. 嗯,是的,谢谢你的提醒,会解决这个问题的。2.typescript自编写此脚本以来不断发展。看起来它可能需要一些更新,你当然是对的。我希望它可以作为您实现目标的起点。
2021-04-22 03:45:55
很可爱,但你有typeof(ParticleKind)你的Enum<T>当然应该是typeof(T)您还需要更新boolboolean用于更高的 TypeScript 版本
2021-05-04 03:45:55
另请注意:这会破坏类中的枚举属性
2021-05-08 03:45:55

这是我解决它的方法。使用属性声明您的 C# 类,然后将生成 .d.ts 文件(使用 T4 转换)。nuget 上有一个包,源代码可在 github 上找到我仍在从事该项目,但支持非常广泛。

我分叉了这个项目并在这里添加了淘汰赛支持:github.com/omniscient/t4ts
2021-04-25 03:45:55