[javascript] TypeScript 프로젝트에서 기존 C # 클래스 정의를 재사용하는 방법

그냥 사용을 시작하겠습니다 TypeScript엔티티 프레임 워크 도메인 모델이 이미있는 MVC 프로젝트에 속하는 HTML 클라이언트 프로젝트에서 . 두 팀이이 작업을 수행 할 것이므로 두 프로젝트 (클라이언트 측과 서버 측)를 완전히 분리하고 싶습니다. JSON과 REST는 객체를주고받는 데 사용됩니다.

물론 domain클라이언트 측의 객체는 서버 측의 객체와 일치해야합니다. 과거에는 일반적으로이 작업을 수동으로 수행했습니다. POJOTypeScript에서 해당 클래스를 만들기 위해 내 C # 클래스 정의 (특히 내 도메인 모델 의 클래스) 를 재사용하는 방법이 있습니까?



답변

현재 C #을 TypeScript에 매핑하는 것은 없습니다. POCO가 많거나 자주 변경 될 수 있다고 생각되면 변환기를 만들 수 있습니다.

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

export class MyPoco {
    public Name: string;
}

C #에서 자동 생성에 대한 Codeplex에 대한 토론 도 있습니다 .

업데이트를 유지하기 위해 TypeLite는 C #에서 TypeScript 인터페이스를 생성 할 수 있습니다.

http://type.litesolutions.net/


답변

Web Essentials를 사용하면 .d.ts저장할 때 C # 파일을 TypeScript 파일 로 컴파일 할 수 있습니다. 그런 다음 .ts파일 에서 정의를 참조 할 수 있습니다.

여기에 이미지 설명 입력


답변

위의 TypeLite 및 T4TS는 모두 좋아 보였고 TypeLite를 선택하여 지원을 받기 위해 분기했습니다.

  • ValueTypes ,
  • Nullables
  • camelCasing (TypeScript 루트 문서는 낙타를 사용하며 C #과 함께 사용하면 너무 좋습니다)
  • 공용 필드 (깨끗하고 읽기 쉬운 POCO를 좋아하고 C # 컴파일러도 쉽게 만들 수 있음)
  • 모듈 생성 비활성화

그런 다음 C # 인터페이스가 필요 했고 이제 제 것을 구울 때라고 생각하고 필요한 작업을 수행하는 간단한 T4 스크립트를 작성했습니다. Enums 도 포함됩니다 . 리포지토리가 필요하지 않으며 T4의 100 줄 미만입니다.

사용법
라이브러리, 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 클래스에서 서비스 인터페이스를 만드는 것입니다.


답변

vscode를 사용하는 경우 내 확장 csharp2ts 를 사용할 수 있습니다 .

붙여 넣은 C # 코드를 선택하고 Convert C# to TypeScript명령 팔레트 여기에 이미지 설명 입력
A 변환 예제 에서 명령을
실행하기 만하면됩니다 .

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


답변

이 문제를 해결하는 방법은 다음과 같습니다. 속성을 사용하여 C # 클래스를 선언하면 .d.ts 파일이 생성됩니다 (T4 변환 사용). 거기의 nuget에 패키지 소스는 github에 볼 수 있습니다 . 나는 여전히 프로젝트를 진행하고 있지만 지원은 상당히 광범위합니다.


답변

Visual Studio를 사용하는 경우 입력기 확장을 추가합니다.

Visual Studio 갤러리

웹 사이트 / 문서

최신 정보

웹 필수가 VS 2015에 설치, 당신은 클래스 파일을 마우스 오른쪽 단추로 클릭 한 다음> 웹 필수> 컨텍스트 메뉴에서 타이프 라이터 인텔리 파일을 만듭니다.


답변

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; }
        }
    }
  3. 프로젝트 재 구축
  4. %Your_Project_Directory%/Scripts/project.ts파일 에서 생성 된 TypeScript 코드를 찾아 수동으로 프로젝트에 추가

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. project.ts다른 TypeScript 코드에서 모든 POCO 및 참조 에 대해 동일하게 수행하십시오 .

문서 위키 에서 자세한 내용보기