Como reutilizar definições de classe C # existentes em projetos TypeScript

121

Vou começar a usar TypeScriptno meu projeto de cliente HTML, que pertence a um projeto MVC com um modelo de domínio de estrutura de entidade já existente. Quero que meus dois projetos (lado do cliente e lado do servidor) sejam totalmente separados, pois duas equipes trabalharão nisso ... JSON e REST são usados ​​para comunicar objetos de um lado para outro.

Obviamente, meus domainobjetos no lado do cliente devem corresponder aos objetos no lado do servidor. No passado, eu normalmente fazia isso manualmente. Existe uma maneira de reutilizar minhas definições de classe C # (especialmente das POJOclasses no meu modelo de domínio) para criar as classes correspondentes no TypeScript "?

pabloelustondo
fonte
Não, eles são idiomas totalmente diferentes.
Hans Passant
6
Sim, eu quis dizer POCO. Eu sei que eles são idiomas totalmente diferentes ... mas seria ótimo, de alguma forma, evitar digitar tudo isso de novo ... Eu acho que por enquanto vou copiar e colar meu código c # .. e refatorar qualquer coisa até que seja compilado TypeScript ... dessa forma, tenho certeza de que não digitei um atributo errado .. e me ajude a não ter que me lembrar. Mas isso claramente não parece nada agradável.
Pabloelustondo 18/10/12
1
Também estou interessado na outra direção - das classes de modelo Typescript às classes de modelo C #, desserializáveis ​​bidirecionalmente através do JSON.
Jason Kleban
Eu tenho olhado para o mesmo e eu só tropeçou em este plugin Gulp embora eu não sei quanto apoio existe para isso
Luke T O'Brien

Respostas:

54

No momento, não há nada que mapeie C # para TypeScript. Se você tem muitos POCOs ou acha que eles podem mudar com frequência, pode criar um conversor - algo simples ao longo das linhas de ...

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

Para

export class MyPoco {
    public Name: string;
}

Há também uma discussão no Codeplex sobre a geração automática de c # .

Apenas para manter as coisas atualizadas, o TypeLite pode gerar interfaces TypeScript a partir do C #:

http://type.litesolutions.net/

Fenton
fonte
Yeahp, algo como isto é o que eu estava pensando em fazer manualmente .. bom. Não tenho certeza se tenho tempo para escrever um conversor agora .. mas sim, essa seria a ideia. Obrigado. Pode ser que a Microsoft esteja fazendo isso agora mesmo quando falamos.
Pabloelustondo 19/10/12
Você pode fazer isso de duas maneiras: ... Gere arquivos .ts com a ajuda da EnvDTE Automation ou usando o Mef Directory Catalog e o Reflection / Introspection. Eu prefiro o segundo, pois não depende do visual.
19412 Arek Bal
1
Eu estava começando a usar o dardo e me deparei com o mesmo problema de como compartilhar tipos entre c # e javascript. Eu esperava que esse problema fosse resolvido pelo Typescript, mas parece que a resposta ainda não está. Eu também fiquei um pouco mimado pelo compilador saltarelle que compilou c # para javascript bastante saltarelle-compiler.com
BraveNewMath
2
@ DanielHarvey As enums são geradas corretamente pelo TypeLite, provavelmente corrigidas desde o seu comentário.
pauloya 8/07/14
1
TypeScriptPaste irá converter C # em TypeType. Você precisa ter o compilador Roslyn, o que significa Visual Studio 2015, mas funciona muito bem. Não é 100% e eu tive que emburrecer algum código - convertendo foreach em loops, escrevendo minha própria classe List <T>, por exemplo, e você deve estruturar o código para que fique "puro" apenas com estruturas de dados internas para trabalhar com, mas era um preço pequeno a pagar por poder modificar e testar o código no VS e depois 'compilar' o Javascript via TypeScript.
John Mott
36

O Web Essentials permite compilar arquivos C # em arquivos TypeScript .d.tsao salvar. Então você pode fazer referência às definições dos seus .tsarquivos.

insira a descrição da imagem aqui

VB
fonte
Talvez você esteja confundindo arquivos .ts e c #? Não é possível encontrar esta opção #
214 Flores Flores
1
Mas depois de algumas pesquisas, achei o que você quis dizer ... realmente bastante útil.
Flores
2
Na verdade, não é, tenho certeza de que a operação não compila nada, gera código. Isso me confundiu, mas não está 99% correto, eu vou te dar isso ;-) #
Flores Flores
1
Seria mais útil se pudéssemos configurar seu namespace e alguma personalização.
Farshid Saberi
5
Agora você precisa instalar o 'Gerador de definições TypeScript' manualmente para usá-lo - veja aqui
Taran
24

TypeLite e T4TSs acima pareciam bons, basta escolher um, TypeLite, bifurcou-o para obter suporte para

  • ValueTypes ,
  • Anuláveis
  • camelCasing (o documento raiz TypeScript usa camelos, e isso é muito bom em conjunto com C #)
  • campos públicos (amam POCOs limpos e legíveis, também facilita o compilador C #)
  • desativar a geração do módulo

Então eu precisava de interfaces C # e pensei que era hora de preparar minhas próprias coisas e escrevi um script T4 simples que apenas faz o que eu preciso. Também inclui Enums . Não é necessário repo, apenas <100 linhas de T4.

Uso
Nenhuma biblioteca, nenhum NuGet, apenas este arquivo T4 simples e simples - use "adicionar item" no Visual Studio e escolha qualquer modelo T4. Em seguida, cole isso no arquivo Adapte todas as linhas com "ACME". Para cada classe C #, adicione uma linha

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

A ordem importa, qualquer tipo conhecido será usado nas seguintes interfaces. Se você usar apenas interfaces, a extensão do arquivo poderá ser .d.ts . Para enumerações, você precisará de um arquivo .ts , pois uma variável é instanciada.

Personalização
Hackeie o script.

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

O próximo nível do script será criar a interface de serviço da classe MVC JsonController.

citykid
fonte
1
Muito fofo, mas você tem typeof(ParticleKind)no seu Enum<T>. Certamente isso deveria ser typeof(T)? Também é preciso atualização boola ser booleanpara versões do texto dactilografado posteriores
Ido Codificação
Também nota: Isto quebra com propriedades ENUM em aulas
Ido Codificação
1. Uhh, sim, obrigado pelo aviso, vai consertar isso. 2. O texto datilografado evoluiu desde a escrita deste script. Parece que pode precisar de alguma atualização, você certamente está certo. Espero que sirva como ponto de partida para seu próprio objetivo.
Citykid 13/09/16
1
Eu o converti em uma biblioteca auxiliar, corrigi os bugs e agora uso apenas entradas de linha única nos meus arquivos TT para gerar interfaces e os novos const enums. Obrigado pelo exemplo. Foi muito próximo e me deu um resultado de trabalho muito mais rápido.
Gone Coding
23

Se você usa o vscode, pode usar minha extensão csharp2ts, que faz exatamente isso.

Você acabou de selecionar o código C # colado e executar o Convert C# to TypeScriptcomando na paleta de comandos insira a descrição da imagem aqui Um exemplo de conversão:

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

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

para

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

    /**Person name */
    Name : string;
}
Rafael
fonte
1
Acho que as pessoas estão interessadas em uma solução totalmente automatizada, na qual a compilação com o msbuild gera as definições datilografadas antes de consumi-las. Existe uma maneira de conseguir isso usando o plugin?
22418 Binki
Não, este um plugin VSCode, só funciona dentro do editor e não como um programa autônomo
Rafael
Eu converti essa extensão vscode no módulo do nó, se você quiser através do node.js ou do tytpescript. Você pode verificar o repo aqui: github.com/YuvrajSagarRana/csharp-to-typescript
Sagar Rana Magar
Existe uma maneira de vincular o comando ao atalho do teclado? Por exemplo, selecionaria o código .net e, com a instalação shift + ctrl + c para executar "Convert C # to TypeScript", isso aceleraria o processo. Eu gosto do plugin!
Pawel Cioch
18

Aqui está a minha abordagem para resolvê-lo. Declare suas classes C # com um atributo e os arquivos .d.ts serão gerados (usando transformações T4). Há um pacote no nuget e a fonte está disponível no github . Ainda estou trabalhando no projeto, mas o suporte é bastante extenso.

Christoffer
fonte
I bifurcada este projecto e apoio nocaute adicionado aqui: github.com/omniscient/t4ts
Frank.Germain
18

Se você estiver usando o Visual Studio, adicione a extensão Typewriter.

Galeria do Visual Studio

Site / Documentação

Atualizar

Com o Web Essentials instalado no VS 2015, você pode clicar com o botão direito do mouse no arquivo de classe e, em seguida,> Web Essentials> Criar arquivo Typescript Intellisense no menu de contexto.

Michael Tranchida
fonte
Ele criou o arquivo d.ts para suporte ao intellisense, mas como alguém o usa e qual é o relacionamento com a criação das classes subjacentes? Fui ao WebEssentails e não consigo encontrar nenhum documento. Alguma sugestão? TIA.
precisa saber é o seguinte
@hio Basta fazer referência ao arquivo d.ts em qualquer arquivo .ts que você precise usá-lo. Quando / se você mudar de classe, o arquivo d.ts subjacente será atualizado. (Dica: você pode arrastar e soltar o arquivo d.ts arquivo para o topo de uma .TS arquivo e ele irá criar a referência para você).
Michael Tranchida
Obrigado Michael! Tentei soltar o arquivo d.ts em um arquivo .ts vazio e ele apenas adicionou o arquivo à pasta que o contém. Tentei no VS2015 e no novo VS2017, mesmos resultados. Você conhece algum vídeo ou tutorial que mostra como tudo isso funciona? TIA
howardlo
Tentei soltar o arquivo d.ts em um arquivo .ts no editor e ele criou a referência. Eu acho que entendo agora. Tutorial ainda bem-vindo. Obrigado!
27417 howardlo
@ hlo Desculpe, não conheço nenhum tutorial. Quando vou pela rota do Web Essentials, criei arquivos .ts duplicados porque meus modelos de domínio estão em uma biblioteca de classes e, no código do lado do cliente, geralmente preciso criar os modelos dto ou vm, que o navegador precisa saber sobre. Se você estiver tendo problemas com tudo isso, tente a extensão Typewriter. Ele permite que você tenha seus arquivos de modelo .ts em qualquer lugar que desejar.
Michael Tranchida
15

Experimente o framework Reinforced.Typings. Parece que resolve o seu problema.

  1. Instale-o no NuGet
  2. Navegue até o seu POCO e adicione o [TsInterface]atributo acima dele

    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. Reconstrua seu projeto
  4. Descubra o código TypeScript gerado no %Your_Project_Directory%/Scripts/project.tsarquivo e adicione-o ao projeto manualmente

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. Faça o mesmo para todos os seus POCOs e faça referência project.tsno seu outro código TypeScript.

Veja mais detalhes na wiki de documentação

Pavel B. Novikov
fonte
Adicione o snippet de amostra ao invés de compartilhar apenas a URL
Venkat.R 14/01
Existe wiki com início rápido O_o github.com/reinforced/Reinforced.Typings/wiki
Pavel B. Novikov
Mas ok, vou dar um exemplo aqui :)
Pavel B. Novikov
Não há suporte para .NET Core ( link ) :(
Alex Klaus
5
Chegou o suporte ao @AlexKlaus .NET Core
Pavel B. Novikov
10

Eu criei um pequeno utilitário que pode gerar interfaces TypeScript a partir de classes C #. Está disponível como um pacote NuGet . Documentação detalhada pode ser encontrada na página do projeto .

Lukas Kabrt
fonte
Biblioteca agradável, bom esforço. Infelizmente, não foi possível ajustar o tipo de valor produzido, por exemplo, converter "string" para "KnockoutObservableString" ou "string []" para "KnockoutObservableArray". É algo que está nos planos para o futuro próximo?
root
2
Em vez disso, usei o T4TS, demorou 14 minutos.
root
@root, você realmente não deve converter uma string [] em KnockoutObservableArray nas definições geradas. Você usa essas definições geradas quando realmente está consumindo as instâncias serializadas dessas classes. Agora, você pode estar executando o objeto inteiro através do plug-in de mapeamento, mas eu recomendaria isso. Isso pode ser excessivo e eu sempre prefiro converter manualmente (provavelmente por meio de um ctor) de suas instâncias serializadas de classes C # em classes TypeScript cheias de observáveis. A única vez em que sugiro executá-lo de forma cega pelo plug-in de mapeamento é para um aplicativo no estilo CRUD.
Allen Rice
@Lukas Kabrt, muito obrigado por TypeLite, tem sido extremamente benéfico em nossos projetos e eu escrevi sobre isso brevemente aqui: underwatergorilladome.com/...
Allen Rice
@AllenRice, achei útil ter classes de modelo de exibição Knockout criadas manualmente, que é onde eu uso a abordagem descrita e a combino com uma classe gerada automaticamente, que é um DTO que foi passado pelo plug-in de mapeamento.
root
7

Por favor, dê uma olhada neste biblioteca Typewriter

Ele converte não apenas classes, enumerações, interfaces, etc., mas também os controladores de API, o que é simplesmente incrível.

Além disso, ele faz isso assim que você salva o arquivo .cs de origem, para que não precise acionar nenhuma ferramenta externa. Salve .cs e você será atualizado .ts

harishr
fonte
O melhor é que ele produz arquivos TS ao salvar arquivos CS correspondentes. No entanto, a configuração da pasta de saída é bastante frágil (consulte a discussão aqui ) e requer algum código artesanal.
Alex Klaus #
Eu faço ferramentas de compilação de uso para isso, e essa ferramenta é muito mais poderosa do que a maioria mencionado aqui
harishr
6

Eu tenho uma pequena solução que usa modelos T4 ( ver código-fonte ).

Você vai de qualquer CLR POCO:

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

Para uma interface TypeScript:

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

Você pode usar o projeto de código aberto NSwag : Na GUI, você pode selecionar a classe .NET de uma DLL .NET existente e gerar a interface TypeScript para ela.

O projeto também fornece ferramentas de linha de comando e suporte para modelos T4, bem como geração de código de cliente para controladores de API da Web ...

Rico Suter
fonte
Esteja ciente de que o NSwag irá gerar arquivos TS apenas a partir dos arquivos binários (você também precisa de todas as dependências dos seus binários) ou do arquivo JSON, que o Swagger produz a partir dos arquivos binários.
Alex Klaus #
3

Se você precisar criar um arquivo separado para cada classe / interface TypeScript gerada (por exemplo, de uma "classe única por arquivo"), tente o TypeGen . É uma ferramenta que você pode usar no Console do Gerenciador de Pacotes para gerar arquivos TypeScript com base em suas classes / enums de C #. Atualmente, ele suporta:

  • exportando enums; exportando POCOs como classes ou interfaces TS
  • herança
  • tipos genéricos
  • tipos de coleção / coleção aninhada

além de alguns recursos adicionais. Também é de código aberto (você pode conferir no github ).

JB1
fonte
2

E o contrário?

Confira erecruit TypeScript Translator . Ele vem com suporte para C # pronto para uso, mas na verdade é baseado em modelo (usa Nunjucks para renderização), o que significa que pode gerar qualquer outra coisa - VB.NET, F #, C ++, XML, SQL - o que você puder codificar com um modelo.

Funciona como um programa de console .NET, programa NodeJS (para aqueles que não estão no Windows) ou como uma extensão do Visual Studio , completa com a funcionalidade de gerar em salvar. E inclui suporte ao MSBuild, apenas para deixar seu servidor de compilação feliz. :-)

Fyodor Soikin
fonte
Marquei isso com +1 porque realmente é a melhor solução, o recurso gerador de economia é o assassino.
John Zabroski
2

Você também pode usar isso: https://github.com/pankleks/TypeScriptBuilder

Essa pequena biblioteca gera a definição de tipo TypeScript com base nos tipos C #. Use-o diretamente no seu projeto C # de back-end para gerar código para o seu projeto TypeScript de front-end. Você também pode escrever um aplicativo de console pequeno para gerar código usando ferramentas de pré-compilação.

Funciona na estrutura Full & NET Core!

Instalar por nuget: Install-Package TypeScriptBuilder

Funcionalidades suportadas

  • Resolvendo dependência de tipo
  • Genéricos
  • Herança de tipo
  • Namespaces (módulos)
  • Enums
  • Tipos anuláveis
  • Conversão de dicionário (para objetos indexados TS do tipo forte)
  • Conjunto de atributos de controle de geração de código
  • any para tipos que não podem ser convertidos

Mais descrição: https://github.com/pankleks/TypeScriptBuilder/blob/master/README.md

pankleks
fonte
Apenas tentei TypeScriptBuildere parece excelente até agora; viva o suporte do .NET Core!
Tobias J
1

Os caras dão uma olhada em https://github.com/reinforced/ Reinforced.Typings . Eu tenho jogado com modelos typelite e t4 nos últimos dias e acabei com este projeto. É super simples e funciona como um encanto. Apenas pegue o pacote, modifique o arquivo de configuração (por 10 segundos) e construa. Tudo é feito automaticamente, sem problemas. Abençoe o autor!

O ruim dos modelos T4 é que, uma vez que você constrói a partir do VS, os assemblies digitalizados ficam bloqueados e você deve reiniciar o VS (o quão tolo é isso?). Existem algumas soluções alternativas no T4 Toolbox + algumas diretivas de limpeza do VS, mas nenhuma delas funcionou para mim.

veb
fonte
1

Eu gosto da solução citykid. Eu tinha ampliado um pouco. Portanto, a solução também se baseia na técnica de codegeneração com modelos T4.

Ele pode gerar tipos comuns de TypeScript e declarações de ambiente.

Ele suporta implementações de herança e interface.

Suporta genéricos, matrizes e listas como campos de tipo.

Também se traduz em tipos TypeScript que não são mencionados explicitamente na configuração (por exemplo, importamos o tipo A e na saída TS, você pode encontrar outros tipos: tipos de campos, tipos básicos e interfaces).

Você também pode substituir o nome do tipo.

Enums também são suportadas.

Exemplo de uso (você pode encontrá-lo no repositório do projeto):

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

E você obterá uma saída

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

Verifique a solução completa aqui: https://bitbucket.org/chandrush/cst4ts

Pedra rolando
fonte
1

Você também pode usar o Bridge.net. Desde a versão 1.7, ele suporta a geração de definições TypeScript para tipos de C #. Consulte http://bridge.net/docs/generate-typescript-definitions/

George Birbilis
fonte
Principal problema é quando você Google Search você pode pousar com a pergunta original e nunca aviso de que informações úteis existido uma resposta duplicado / fechado
George Birbilis
Portanto, verifique se o canônico tem as melhores informações. Não poste para várias perguntas. Qualquer discussão adicional sobre isso pode ser levada ao Meta Stack Overflow
Martijn Pieters
1

Eu também gostei muito da resposta do @ citykid, então eu o estendi para criar um espaço de nome inteiro por vez. Basta colocar as classes POCO no espaço para nome e reconstruir os modelos T4. Eu gostaria de saber como gerar arquivos separados para cada um, mas isso não é o fim do mundo.

Você precisa fazer referência aos arquivos .DLL na parte superior (onde estão as classes que deseja) e mencionar os espaços para nome. Todas as linhas para editar estão marcadas com ACME. Principais elogios para @citykid, agradeço!

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

Minha solução foi escrever um pequeno utilitário de codegen que simplesmente pega um assembly de projeto (e faz referência a assemblies) e inicia a varredura de tipos envolvidos na interação entre texto datilografado e c #. Este utilitário gera javascript e d.ts ... A ferramenta é chamada no evento pós-compilação ... funciona como um encanto!

Paul0515
fonte
Não sei por que escolhi produzir js e d.ts ... no momento, ele simplesmente gera .ts ... simples e muito factível.
Paul0515
1
Oi Paul ... você poderia compartilhar o código util conosco. Eu estou olhando apenas para criar um arquivo ts (em um determinado local da pasta) e não um arquivo d.ts como você disse. Isso é algo que seu utilitário pode fazer?
Krishna Teja Veeramachaneni
0

Se estiver interessado, você pode usar o TypedRpc . Seu objetivo não é apenas criar as interfaces no TypeScript, mas criar toda a comunicação com o serviço em .Net usando o protocolo JsonRpc.

Exemplo para uma classe no servidor:

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

Uso do código TypeScript gerado:

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

Confira https://github.com/Rodris/TypedRpc para outros exemplos de como usá-lo.

Rodris
fonte
0

Os Geradores de clientes da API da Web do ASP.NET podem ser mais úteis, menos sobrecarga do que o swagger toolchain e outros durante o SDLC.

Embora os programadores geralmente usem o WebApiClientGen para gerar códigos de API do cliente, este projeto também fornece o POCO2TS.exe, um programa de linha de comando que gera interfaces TypsScript a partir das classes POCO. Você pode usar o Poco2ts.exe ou o componente poco2ts para integrar a geração de código ao seu pipeline de compilação.

ZZZ
fonte
0

Se você deseja convertê-lo através do node.js, pode usar este pacote (csharp-to-typescript). https://www.npmjs.com/package/csharp-to-typescript

código-fonte: 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;
}
Sagar Rana Magar
fonte
0

Se você estiver usando o VSCode, poderá dar uma olhada nessa extensão C # para TypeScript

Converter classe C # em interface TypeScript

Veja como eu posso convertê-lo do código C # em apenas um clique. Obviamente, nem todas as classes serão convertidas, como a fábrica, mas elas são boas o suficiente para o lado do cliente. Nós apenas precisamos da forma dos dados. Às vezes, se eu precisar usar o padrão de visitante, decorarei com métodos adicionais necessários. Demorou apenas 5 segundos para fazer isso. Comparando com um minuto acima, eu poderia dizer que é uma grande vitória.

Veja mais detalhes na minha postagem no blog

trungk18
fonte