TypedSignalR.Client.TypeScript
TypeScript source generator to provide strongly typed SignalR clients by analyzing C# type definitions.
Install / Use
/learn @nenoNaninu/TypedSignalR.Client.TypeScriptREADME
TypedSignalR.Client.TypeScript
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?
- Packages
- Usage
- Transpile the Types Contained in Referenced Assemblies
- Supported Types
- Analyzer
- Streaming Support
- Client Results Support
- MessagePack Hub Protocol Support
- GitHub Actions Integration
- MSBuild Integration
- Related Work
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
- TypedSignalR.Client.TypeScript.Attributes
- TypedSignalR.Client.TypeScript.Analyzer
- TypedSignalR.Client.TypeScript.Generator
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.
Make sure that all your types to be transpiled are within a namespace.
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.
getHubProxyFactorygetReceiverRegister
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()
// ...
Transpile the Types Contained in Referenced Assemblies
By default, only types defined in the project specified by the --project option are targeted for transpiling. By passing the --asm true option, types contained in project/package reference assemblies will also be targeted for transpiling.
$ dotnet tsrts --project path/to/Project.csproj --output generated --asm true
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 sup
Related Skills
node-connect
353.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Writing Hookify Rules
111.7kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
review-duplication
100.7kUse this skill during code reviews to proactively investigate the codebase for duplicated functionality, reinvented wheels, or failure to reuse existing project best practices and shared utilities.
