Giter Club home page Giter Club logo

typedsignalr.client.typescript's Introduction

TypedSignalR.Client.TypeScript

NuGet build-and-test

TypedSignalR.Client.TypeScript is a library/CLI tool that analyzes SignalR hub and receiver type definitions written in C# and generates TypeScript source code to provide strongly typed SignalR clients.

Table of Contents

Why TypedSignalR.Client.TypeScript?

Implementing SignalR Hubs (server-side) in C# can be strongly typed by using interfaces, but the TypeScript SignalR client is not strongly typed. To call Hub methods, we must specify the method defined in Hub using a string. We also have to determine the return type manually. Moreover, registering client methods called from a server also requires specifying the method name as a string, and we must set parameter types manually.

// TypeScript SignalR client
// without TypedSignalR.Client.TypeScript

// Specify a hub method to invoke using string.
await connection.invoke("HubMethod1");

// Manually determine a return type.
// Parameters are cast to any type.
const value = await connection.invoke<number>("HubMethod2", "message", 99);

// Registering a client method requires a string, and parameter types must be set manually.
const func = (message: string, count: number) => {...};
connection.on("ClientMethod", func);
connection.off("ClientMethod", func);

These are very painful and cause bugs.

TypedSignalR.Client.TypeScript aims to generates TypeScript source code to provide strongly typed SignalR clients by analyzing C# interfaces in which the server and client methods are defined. You only need to execute one command to analyze your C# code and generate TypeScript code. Please see the Install Using .NET Tool and Usage sections for more information.

dotnet tsrts --project path/to/Project.csproj --output generated
// TypeScript SignalR client
// with TypedSignalR.Client.TypeScript
// Generated source code

export type HubProxyFactory<T> = {
    createHubProxy(connection: HubConnection): T;
}

export type ReceiverRegister<T> = {
    register(connection: HubConnection, receiver: T): Disposable;
}

// Overload function type
// Because string literal types are used, there is no need to worry about typos.
export type HubProxyFactoryProvider = {
    // In this example, IHub1 and IHub2 are transpiled from C# to TypeScript.
    (hubType: "IHub1"): HubProxyFactory<IHub1>;
    (hubType: "IHub2"): HubProxyFactory<IHub2>;
}

// Overload function type
export type ReceiverRegisterProvider = {
    // In this example, IReceiver1 and IReceiver2 are transpiled from C# to TypeScript.
    (receiverType: "IReceiver1"): ReceiverRegister<IReceiver1>;
    (receiverType: "IReceiver2"): ReceiverRegister<IReceiver2>;
}

export const getHubProxyFactory : HubProxyFactoryProvider = ...; 
export const getReceiverRegister : ReceiverRegisterProvider = ...;
// Usage of generated code.

const hubProxy = getHubProxyFactory("IHub1") // HubProxyFactory<IHub1>
    .createHubProxy(connection); // IHub1

const receiver : IReceiver1 = {...};

const subscription = getReceiverRegister("IReceiver1") // ReceiverRegister<IReceiver1>
    .register(connection, receiver); // Disposable

// We no longer need to specify the method using a string.
await hubProxy.hubMethod1();

// Both parameters and return types are strongly typed.
const value = await hubProxy.hubMethod2("message", 99); // Type inference works.

subscription.dispose();

The example of the actual generated code exists in /samples/console.typescript/generated so please have a look if you are interested.

Packages

Install Using .NET Tool

Use TypedSignalR.Client.TypeScript.Generatorr(CLI Tool) to generate TypeScript source code to provide strongly typed SignalR clients. TypedSignalR.Client.TypeScript.Generatorr can be easily installed using .NET Global Tools. You can use the installed tools with the command dotnet tsts(TypedSignalR.Client.TypeScript).

# install
# TypedSignalR.Client.TypeScript CLI (dotnet tool) requires .NET 7, but your app TFM can use .NET 6, etc.
dotnet tool install --global TypedSignalR.Client.TypeScript.Generator
dotnet tsrts help

# update
dotnet tool update --global TypedSignalR.Client.TypeScript.Generator

Usage

First, add the following packages to your project. TypedSignalR.Client.TypeScript.Analyzer is optional, but recommended.

dotnet add package TypedSignalR.Client.TypeScript.Attributes
dotnet add package TypedSignalR.Client.TypeScript.Analyzer (optional, but recommended.)
dotnet add package Tapper.Analyzer (optional, but recommended.)

By adding TypedSignalR.Client.TypeScript.Attributes package, you can use three attributes.

  • HubAttribute
  • ReceiverAttribute
  • TranspilationSourceAttribute

Then, annotate HubAttribute and ReceiverAttribute to each interface definitions of Hub and Receiver of SignalR. Also, annotate TranspilationSourceAttribute to user-defined types used in the interface definition of Hub and Receiver. Adding this attribute is relatively easy if you add the TypedSignalR.Client.TypeScript.Analyzer to your project.

using Tapper;
using TypedSignalR.Client;

namespace App.Interfaces.Chat;

[Hub] // <- Add Attribute
public interface IChatHub
{
    Task Join(string username);
    Task Leave();
    Task<IEnumerable<string>> GetParticipants();
    Task SendMessage(string message);
}

[Receiver] // <- Add Attribute
public interface IChatReceiver
{
    Task OnReceiveMessage(Message message);
    Task OnLeave(string username, DateTime dateTime);
    Task OnJoin(string username, DateTime dateTime);
}

[TranspilationSource] // <- Add Attribute
public record Message(string Username, string Content, DateTime TimeStamp);

Finally, enter the following command. This command analyzes C# and generates TypeScript code.

dotnet tsrts --project path/to/Project.csproj --output generated

The generated code can be used as follows. There are two important APIs that are generated.

  • getHubProxyFactory
  • getReceiverRegister
import { HubConnectionBuilder } from "@microsoft/signalr";
import { getHubProxyFactory, getReceiverRegister } from "./generated/TypedSignalR.Client";
import { IChatReceiver } from "./generated/TypedSignalR.Client/App.Interfaces.Chat";
import { Message } from "./generated/App.Interfaces.Chat";

const connection = new HubConnectionBuilder()
    .withUrl("https://example.com/hubs/chathub")
    .build();

const receiver: IChatReceiver = {
    onReceiveMessage: (message: Message): Promise<void> => {...},
    onLeave: (username: string, dateTime: string | Date): Promise<void> => {...},
    onJoin: (username: string, dateTime: string | Date): Promise<void> => {...}
}

// The argument of getHubProxyFactory is a string literal type, not a string type.
// Therefore, there is no need to worry about typos.
const hubProxy = getHubProxyFactory("IChatHub")
    .createHubProxy(connection);

// Also, the argument of getReceiverRegister is a string literal type, not a string type.
// Therefore, again, there is no need to worry about typos.
const subscription = getReceiverRegister("IChatReceiver")
    .register(connection, receiver)

await connection.start()

await hubProxy.join(username)

const participants = await hubProxy.getParticipants()

// ...

Supported Types

TypedSignalR.Client.TypeScript uses a library named nenoNaninu/Tapper to convert C# types to TypeScript types. Please read Tapper's README for details on the correspondence between C# types and TypeScript types. Here is a brief introduction of which types are supported.

Built-in Supported Types

bool byte sbyte char decimal double float int uint long ulong short ushort object string Uri Guid DateTime System.Nullable<T> byte[] T[] System.Array ArraySegment<T> List<T> LinkedList<T> Queue<T> Stack<T> HashSet<T> IEnumerable<T> IReadOnlyCollection<T> ICollection<T> IList<T> ISet<T> Dictionary<TKey, TValue> IDictionary<TKey, TValue> IReadOnlyDictionary<TKey, TValue> Tuple

User Defined Types

Of course, you can use user-defined types as well as Built-in Supported Types. To transpile C# user-defined types to TypeScript types, annotate TranspilationSourceAttribute.

using Tapper;

[TranspilationSource] // <- Add attribute!
public class CustomType
{
    public List<int>? List { get; }
    public int Value { get; }
    public Guid Id { get; }
    public DateTime DateTime { get; }
}

[TranspilationSource] // <- Add attribute!
public enum MyEnum
{
    Zero = 0,
    One = 1,
    Two = 1 << 1,
    Four = 1 << 2,
}

[TranspilationSource] // <- Add attribute!
public record CustomType2(float Value, DateTime ReleaseDate);

Analyzer

User-defined types used in parameters and return values of methods defined within interfaces annotated with Hub or Receiver must be annotated with TranspilationSource. The Analyzer checks in real-time whether this rule is followed. If not, the IDE will tell you.

analyzer

Streaming Support

SignalR supports both server-to-client streaming and client-to-server streaming.

TypedSignalR.Client.TypeScript supports both server-to-client streaming and client-to-server streaming. If you use IAsyncEnumerable<T>, Task<IAsyncEnumerable<T>>, or Task<ChannelReader<T>> for the method return type, it is analyzed as server-to-client streaming. And if IAsyncEnumerable<T> or ChannelReader<T> is used in the method parameter, it is analyzed as client-to-server streaming.

When using server-to-client streaming, a single CancellationToken can be used as a method parameter (Note: CancellationToken cannot be used as a parameter except for server-to-client streaming).

// C# source code
[Hub]
public interface IMyStreamingHub
{
    // Server-to-Client streaming
    // Return type : IAsyncEnumerable<T> or Task<IAsyncEnumerable<T>> or Task<ChannelReader<T>>
    // Parameter : CancellationToken can use.
    Task<ChannelReader<MyStreamItem>> ServerToClientStreaming(MyType instance, int init, CancellationToken cancellationToken);

    // Client-to-Server streaming
    // Return type : Task (not Task<T>)
    // Parameter : IAsyncEnumerable<T> and ChannelReader<T> can use as stream from client to server.
    Task ClientToServerStreaming(MyType instance, ChannelReader<MyStreamItem> stream);
}
// Usage in TypeScript
// Parameters and return types are strongly typed by generated TypeScript code

const connection: HubConnection = ...;

const hubProxy = getHubProxyFactory("IMyStreamingHub")
    .createHubProxy(connection);

await connection.start();

const instance: MyType = ...;

// subscribe server to client streaming message
hubProxy.serverToClientStreaming(instance, 99) // IStreamResult<MyStreamItem>
    .subscribe({
        next: (value: MyStreamItem): void => {
            console.log(value)
        },
        error: (err: any): void => {
            console.log(err)
        },
        complete: (): void => {
            console.log("complete")
        }
    });

const subject = new Subject<MyStreamItem>(); // stream

// set client to server stream
await hubProxy.clientToServerStreaming(instance, subject);

const item: MyStreamItem = ...;
subject.next(item); // write item to stream
subject.next(item);
subject.complete();

Client Results Support

.NET 7 and later, you can use client results.

TypedSignalR.Client.TypeScript supports client results. If you use Task<T> for the method return type in the receiver interface, you can use client results.

// C# source code
[Receiver]
public interface IMyHubReceiver
{
    // Return type: Task<T> 
    Task<Guid> GetGuidFromClient();
}
// Usage in TypeScript
// Parameters and return types are strongly typed by generated TypeScript code

const connection: HubConnection = ...;

const receiver: IMyHubReceiver = {
    getGuidFromClient: (): Promise<string> => {
        // return value.
        return Promise.resolve("ba3088bb-e7ea-4924-b01b-695e879bb166");
    }
}

const subscription = getReceiverRegister("IMyHubReceiver")
    .register(connection, receiver);

MessagePack Hub Protocol Support

This tool can generate TypeScript code to use the MessagePack Hub Protocol. When serializing a user-defined type, use a property name as a key (in other words, it should be serialized as a map, not an array). Therefore, apply [MessagePackObject(true)] to a user-defined type, or use ContractlessStandardResolver. The default configuration for MessagePack Hub Protocol includes the ContractlessStandardResolver.

Default Configuration in ASP.NET Core

Calling AddMessagePackProtocol is required to use the MessagePack Hub Protocol. For more information, please see the official documentation.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR()
    .AddJsonProtocol()
    .AddMessagePackProtocol();

If you do not set any options in AddMessagePackProtocol, use the following command.

dotnet tsrts --project path/to/Project.csproj --output generated --serializer MessagePack --naming-style none --enum name

Recommended Configuration

SignalR MessagePack Hub Protocol serializes an enum as a string by default. The following configuration is required to serialize an enum as an integer value.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR()
    .AddJsonProtocol()
    .AddMessagePackProtocol(options =>
    {
        options.SerializerOptions = MessagePackSerializerOptions.Standard
            .WithResolver(ContractlessStandardResolver.Instance)
            .WithSecurity(MessagePackSecurity.UntrustedData);
    });

If you set up the above configuration, use the following command

dotnet tsrts --project path/to/Project.csproj --output generated --serializer MessagePack --naming-style none

Related Work

typedsignalr.client.typescript's People

Contributors

backfromexile avatar chanos-dev avatar davidfowl avatar dependabot[bot] avatar montellese avatar nenonaninu avatar rafaelsc avatar skyppid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

typedsignalr.client.typescript's Issues

System.ArgumentNullException in setup code

Hey, thanks a lot for your work. I've already tried Tapper to transpile my DTOs into TypeScript which works great but I'd also like to transpile my SignalR hub. Unforunately I always get the following output when running dotnet tsrts --project myproject.csproj --output generated:

Start loading the csproj of path\to\myproject.csproj.
Create Compilation...
======== Exception ========
System.ArgumentNullException: Value cannot be null. (Parameter 'key')
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value)
   at Tapper.DefaultTypeMapperProvider.AddTypeMapper(ITypeMapper typeMapper)
   at TypedSignalR.Client.TypeScript.App.TranspileCore(Compilation compilation, String outputDir, NewLineOption newLine, Int32 indent, Boolean referencedAssembliesTranspilation, SerializerOption serializerOption, NamingStyle namingStyle, EnumStyle enumStyle, MethodStyle methodStyle, Boolean enableAttributeReference) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript.Generator/App.cs:line 101
   at TypedSignalR.Client.TypeScript.App.Transpile(String project, String output, NewLineOption newLine, Boolean assemblies, SerializerOption serializer, NamingStyle namingStyle, EnumStyle enum, MethodStyle method, Boolean attribute) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript.Generator/App.cs:line 55

I've reduced my project to the following C# code:

using System.Threading.Tasks;
using TypedSignalR.Client;

namespace MyProject
{
    [Hub]
    public interface IServer
    {
        Task Connect();
    }
}

Do you have any idea what the problem could be. Looking at the exception the problem seems to be that

Assign = compilation.GetTypeByMetadataName("System.Collections.Generic.IAsyncEnumerable`1")!;
results in Assign being null.

Support classes from different assembly in Typescript Client generation

Would it be possible for the 'tsrts' tool to support generating Typescript clients when the User Defined types in the interfaces for the [Hub] and [Receiver], are defined in a different assembly ?

Currently the type

using Tapper;
namespace TestProject.Library;

[TranspilationSource]
public class TestClass
{
    public string Test { get; set; }
}

fails with:

System.InvalidOperationException: TestProject.Library.TestClass is not supported.
   at Tapper.DefaultTypeMapperProvider.GetTypeMapper(ITypeSymbol type)
   at Tapper.TypeMappers.TypeMapper.MapTo(ITypeSymbol typeSymbol, ITranspilationOptions options)
   at TypedSignalR.Client.TypeScript.InterfaceTranspiler.WriteParameters(IMethodSymbol methodSymbol, ITranspilationOptions options, CodeWriter& codeWriter) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/InterfaceTranspiler.cs:line 134
   at TypedSignalR.Client.TypeScript.InterfaceTranspiler.AddInterface(INamedTypeSymbol interfaceSymbol, SpecialSymbols specialSymbols, ITranspilationOptions options, CodeWriter& codeWriter) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/InterfaceTranspiler.cs:line 102
   at TypedSignalR.Client.TypeScript.InterfaceTranspiler.Transpile(IEnumerable`1 interfaceTypes) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/InterfaceTranspiler.cs:line 40
   at TypedSignalR.Client.TypeScript.TypedSignalRCodeGenerator.Generate() in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/TypedSignalRCodeGenerator.cs:line 45
   at TypedSignalR.Client.TypeScript.App.TranspileCore(Compilation compilation, String outputDir, String newLine, Int32 indent, SerializerOption serializerOption, NamingStyle namingStyle, EnumNamingStyle enumNamingStyle) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript.Generator/App.cs:line 107
   at TypedSignalR.Client.TypeScript.App.Transpile(String project, String output, String newLine, String serializer, String namingStyle, String enumNamingStyle) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript.Generator/App.cs:line 67

when trying to transpile a Typescript client from the following interface:

using TypedSignalR.Client.TypeScript;
using TestProject.Library;
namespace TestProject.ClientInterface;

[Hub]
public interface ITest
{
    Task<TestClass> TestMethod(TestClass message);
}

This only seems to be an issues when the namespaces 'TestProject.Library' and 'TestProject.ClientInterface' are defined in different assemblies.

CancellationToken not supported

Hello,

First, thank you for this project.

I'm sure I'm not using it correctly.

Here are snippets of my code and usage and reported error :

IHub.cs

IAsyncEnumerable<StreamingLinesResponse> StreamEntitiesAsyncEnumerable(
        StreamingEntitiesRequest request,
        CancellationToken cancellationToken
    );

HubImpl.cs

[SignalRMethod]
    public async IAsyncEnumerable<StreamingLinesResponse> StreamEntitiesAsyncEnumerable(
        StreamingEntitiesRequest request,
        [EnumeratorCancellation] CancellationToken cancellationToken = default
    )
    {
        await foreach (StreamingLinesResponse i in _tableStreamer.StreamEntitiesAsync(request, cancellationToken)
                           .WithCancellation(cancellationToken))
            yield return i;
    }

Call

 dotnet tsrts --project .\My.Web.Api\My.Web.Api.csproj --output .\My.Web.Front\src\MySignalRClient
======== Exception ========
System.InvalidOperationException: System.Threading.CancellationToken is not supported.
   at Tapper.DefaultTypeMapperProvider.GetTypeMapper(ITypeSymbol type)
   at Tapper.TypeMappers.TypeMapper.MapTo(ITypeSymbol typeSymbol, ITranspilationOptions options)
   at TypedSignalR.Client.TypeScript.Templates.MethodSymbolExtensions.<>c__DisplayClass5_0.<ParametersToTypeArray>b__0(IParameterSymbol x) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/Templates/MethodSymbolExtensions.cs:line 83
   at System.Linq.Enumerable.SelectArrayIterator`2.MoveNext()
   at System.String.Join(String separator, IEnumerable`1 values)
   at TypedSignalR.Client.TypeScript.Templates.MethodSymbolExtensions.ParametersToTypeArray(IMethodSymbol methodSymbol, ITypedSignalRTranspilationOptions options) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/Templates/MethodSymbolExtensions.cs:line 84
   at TypedSignalR.Client.TypeScript.Templates.MethodSymbolExtensions.WrapLambdaExpressionSyntax(IMethodSymbol methodSymbol, ITypedSignalRTranspilationOptions options) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/Templates/MethodSymbolExtensions.cs:line 16
   at TypedSignalR.Client.TypeScript.Templates.ApiTemplate.TransformText() in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/Templates/ApiTemplate.cs:line 141
   at TypedSignalR.Client.TypeScript.ApiGenerator.Generate(IReadOnlyList`1 hubTypes, IReadOnlyList`1 receiverTypes) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/ApiGenerator.cs:line 38
   at TypedSignalR.Client.TypeScript.TypedSignalRCodeGenerator.Generate() in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript/TypedSignalRCodeGenerator.cs:line 43
   at TypedSignalR.Client.TypeScript.App.TranspileCore(Compilation compilation, String outputDir, NewLineOption newLine, Int32 indent, Boolean referencedAssembliesTranspilation, SerializerOption serializerOption, NamingStyle namingStyle, EnumStyle enumStyle, MethodStyle methodStyle, Boolean enableAttributeReference) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript.Generator/App.cs:line 125
   at TypedSignalR.Client.TypeScript.App.Transpile(String project, String output, NewLineOption newLine, Boolean assemblies, SerializerOption serializer, NamingStyle namingStyle, EnumStyle enum, MethodStyle method, Boolean attribute) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript.Generator/App.cs:line 55

Thank you for your help !

Stéphane

InvalidOperationException when using inner records

I am seeing an InvalidOperationException when trying to transpile the following record inside another record:

[TranspilationSource]
public record DestinationListDTO
    (IReadOnlyCollection<DestinationListDTO.Destination> Destinations)
{
    [TranspilationSource]
    public record Destination(
           short? Address,
           string? Label1,
           string? Label2,
           short? Source)
    {
    }
}

The error is below. I can resolve the error by moving the "Destination" definition outside of the "DestinationListDTO" record. So something not liking the record/custom type inside another record.

I've removed some of my namespace, but you get the idea.

Transpile xxx.DestinationListDTO... xxx.DestinationListDTO can not be transpiled. ======== Exception ======== System.InvalidOperationException: xxx.DestinationListDTO.Destination is not supported. at Tapper.DefaultTypeMapperProvider.GetTypeMapper(ITypeSymbol type) at Tapper.TypeMappers.IReadOnlyCollection1TypeMapper.MapTo(ITypeSymbol typeSymbol, ITranspilationOptions options) at Tapper.TypeMappers.TypeMapper.MapTo(ITypeSymbol typeSymbol, ITranspilationOptions options) at Tapper.TypeTranslators.DefaultMessageTypeTranslator.Translate(CodeWriter& codeWriter, INamedTypeSymbol typeSymbol, ITranspilationOptions options) at Tapper.TypeScriptCodeGenerator.AddType(INamedTypeSymbol typeSymbol, CodeWriter& writer) at Tapper.Transpiler.Transpile() at TypedSignalR.Client.TypeScript.App.TranspileCore(Compilation compilation, String outputDir, NewLineOption newLine, Int32 indent, Boolean referencedAssembliesTranspilation, SerializerOption serializerOption, NamingStyle namingStyle, EnumStyle enumStyle, MethodStyle methodStyle, Boolean enableAttributeReference) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript.Generator/App.cs:line 133 at TypedSignalR.Client.TypeScript.App.Transpile(String project, String output, NewLineOption newLine, Boolean assemblies, SerializerOption serializer, NamingStyle namingStyle, EnumStyle enum, MethodStyle method, Boolean attribute) in /home/runner/work/TypedSignalR.Client.TypeScript/TypedSignalR.Client.TypeScript/src/TypedSignalR.Client.TypeScript.Generator/App.cs:line 55

Type-only imports should be imported using `import type`

Hi there,

when the TypeScript configuration option isolatedModules is active, then the compilation of the generated .ts files fails as they only import types but the imports are not properly marked as such.
Type-only imports should use import type { Type } instead of import { Type }.
This change should not be an issue for any TypeScript project that uses TypeScript >=3.8.

Because of the issue mentioned above, running my Vue3 project with vite fails with a runtime error like this
Uncaught SyntaxError: The requested module '/src/_generated/Namespace.Hubs.ts' does not provide an export named 'MyType' (at Namespace.Hubs.ts:6:23).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.