Dekiru.TypeScriptClientBuilder
6.2.3
Prefix Reserved
See the version list below for details.
dotnet add package Dekiru.TypeScriptClientBuilder --version 6.2.3
NuGet\Install-Package Dekiru.TypeScriptClientBuilder -Version 6.2.3
<PackageReference Include="Dekiru.TypeScriptClientBuilder" Version="6.2.3" />
<PackageVersion Include="Dekiru.TypeScriptClientBuilder" Version="6.2.3" />
<PackageReference Include="Dekiru.TypeScriptClientBuilder" />
paket add Dekiru.TypeScriptClientBuilder --version 6.2.3
#r "nuget: Dekiru.TypeScriptClientBuilder, 6.2.3"
#:package Dekiru.TypeScriptClientBuilder@6.2.3
#addin nuget:?package=Dekiru.TypeScriptClientBuilder&version=6.2.3
#tool nuget:?package=Dekiru.TypeScriptClientBuilder&version=6.2.3
TypeScript Client Builder
A .NET library that automatically generates TypeScript client code and DTOs from ASP.NET Core controllers. Reduce boilerplate and keep your frontend and backend in sync.
Features
- Automatic Client Generation: Generates TypeScript HTTP client methods from your ASP.NET Core controllers
- DTO Export: Automatically exports C# DTOs to TypeScript interfaces
- Enum Support: Multiple enum export options (numbers, strings, unions, const enums)
- Type Safety: Full type safety between your C# API and TypeScript client
- Inheritance Support: Optional support for inheritance chains in generated types
- Record Type Support: C# records are automatically converted to TypeScript interfaces
- NDJSON Streaming: Server-sent streaming with automatic callback generation
- Customizable: Extensive configuration options for indentation, naming, and behavior
- Checksum Optimization: Skip regeneration when nothing has changed
- XML Documentation: Import your XML documentation comments into TypeScript
- Flexible Parameters: Support for named parameters, headers, event callbacks, and more
Installation
Install via NuGet:
dotnet add package Dekiru.TypeScriptClientBuilder
Or via Package Manager Console:
Install-Package Dekiru.TypeScriptClientBuilder
Quick Start
Basic Usage
Add the following to your ASP.NET Core application (typically in Program.cs):
using TypeScriptClientBuilder;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
// Generate TypeScript client
ClientBuilder.Build(new ClientConfiguration
{
Output = "ClientOutput"
});
app.Run();
This will scan all your controllers and generate TypeScript files in the ClientOutput directory.
Example Controller
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get(CancellationToken cancellationToken)
{
// Your implementation
}
}
This generates a TypeScript client with type-safe methods to call your API.
Helpful for LLMs
Library Architecture & Namespaces
The TypeScriptClientBuilder library uses the following main namespaces:
TypeScriptClientBuilder- Root namespace for the libraryTypeScriptClientBuilder.Attributes- Custom attributes for controlling generation (ClientBuilderAttribute, UnionTypeAttribute, etc.)TypeScriptClientBuilder.Primitives- Core data models representing parsed controller structure (Controller, Method, Parameter, TsType)TypeScriptClientBuilder.Utils- Utility classes for code generation (TypeNameResolver, TypeScriptWriter, TypeExporter)TypeScriptClientBuilder.Streaming- Streaming result types (NdJsonResult)
Entry Points & Configuration
Main Entry Point:
TypeScriptClientBuilder.ClientBuilder.Build(ClientConfiguration configuration)
Configuration Object:
The ClientConfiguration class contains all library settings for customization:
- Output directory, file cleaning, checksum validation
- Type generation preferences (inheritance, partials, nullability)
- Method signature options (named parameters, generic methods, event callbacks)
- Enum export strategies (strings, union types, const enums)
- Advanced options (XML documentation, includes, custom type formatters)
Core Components Deep Dive
1. Controller Parsing (ExportService.CreateModel())
- Scans assemblies for
[ApiController]decorated classes - Extracts HTTP verb information (HttpGet, HttpPost, etc.)
- Parses route templates from controller and method attributes
- Collects method parameters and metadata
2. Type Export Pipeline (TypeExporter.Export)
- Recursively processes all types used in returned values and parameters
- Handles type relationships: DTOs, enums, generic types, arrays, dictionaries
- Tracks exported types to prevent duplication
- Applies nullable type transformations
3. Type Resolution Engine (TypeNameResolver.Resolve)
This component converts C# types to TypeScript types with intelligent handling:
System.String → string
int? → { [key]?: T };
MyNamespace.UserDto → { name: string; id: number; };
List<Item> → Item[];
Dictionary<string, User> → { [key: string]: User };
Task<T> → Promise<T>;
IEnumerable<T> → T[];
NdJsonResult<T> → T (with streaming callbacks)
4. TypeScript Code Generation (TypeScriptWriter)
Handles code generation for different export types:
BeginInterface()- Defines TypeScript interfaces with appropriate propertiesBeginEnum()- Creates enum definitions based on EnumTypes configurationWriteStartTSDoc()- Generates JSDoc comments from XML documentation- Block nesting with automatic indentation management
Type System Documentation
Primitives Namespace Classes:
Controller- Represents a parsed controller with methods collectionMethod- Represents a controller action with HTTP verb, route, and type infoParameter- Represents a method parameter with binding type and TypeScript typeTsType- Core CLR type representation with type system operations (IsArray, IsEnum, IsDto, GenericTypeArguments)Description- XML documentation wrapper for methods and properties
Utils Namespace Classes:
TypeNameResolver- Complex type mapping from C# to TypeScript with context-aware transformationsTypeExporter- Type management, export tracking, and registrationTypeScriptWriter- Low-level TypeScript code generation with block managementTypeNameResolver- Type name resolution and transformation for proper output
Streaming Namespace:
NdJsonResult- Server-sent streaming result type for large data handling
Attribute System:
ClientBuilderAttribute(with ClientBuilderSettings flags) - Controls generation behavior at controller/method levelClientBuilderMethodNameAttribute- Customizes generated method namesClientBuilderReturnsUrlAttribute/ClientBuilderRedirectAttribute- Controls file download behaviorAddQueryParameterAttribute- Adds implicit query parametersUnionTypeAttribute- Generates string union types like"value1" | "value2" | "value3"TypedIdOfAttribute- Overrides property types for custom type transformationsPartialAttribute- Creates Partial<T> types for partial dataKeyOfAttribute- Generates keyof T typesNullableAttribute/OptionalAttribute- Explicit property nullability/optional markers
Generation Workflow
- Controller Discovery - Assemblies scanned for controllers with [ApiController] attribute
- Method Extraction - HTTP verb attributes (HttpGet, HttpPost, etc.) trigger method discovery
- Type Analysis - TypeScript type resolution for return types and parameters
- Export Registration - Controllers and DTOs registered for code generation
- Type Normalization - Enums, nullable types, and generic types processed
- Code Writing - TypeScript interfaces, enums, and client methods written to Output directory
- File Structure
Generated output directory contains:
Output/
├── HttpClient.ts # Base client implementation
├── Enums.ts # All enum definitions
├── Dto.ts # All DTO interfaces
└── <ControllerName>.ts # Controller-specific methods
Programmatic Usage Patterns
Custom Type Formatting:
TypeFormatter = type => type.Name + "Dto"
Wildcard Includes:
Includes = new HashSet<string>
{
"MyApi.Types.*", // Include all types in namespace
"MyApi.Controllers.*" // Include all controller exports
}
Custom Logging:
LoggingCallback = message => Logger.Info($"[ClientBuilder] {message}")
Complete API Reference Summary
Key Enums:
ExportType- (Controller, DTO, Enum) Export categoryFileResultBehavior- (Redirect, Uri) File download return strategyEnumTypes(Flags) - (None, Strings, Union, Const) Enum export optionsClientBuilderSettings(Flags) - (AddHeader, AddEventCallback, AddReturnXhrFlag, OmitHeader, OmitEventCallback, OmitReturnXhrFlag)
Core Classes:
ClientBuilder.Build(ClientConfiguration config)- Initializes and runs generationTypeExporter.GetDTOs()- Returns collected DTO typesTypeExporter.GetEnums()- Returns collected enum types
Common TypeScript Types Generated:
- Interfaces for C# classes and records
- Type-safe method signatures with parameter objects
- Enum translations based on EnumTypes configuration
- nullability handling with ? suffix or optional<T>
This architecture enables the library to provide end-to-end TypeScript client generation while maintaining flexibility for advanced use cases and customizations.
Configuration Options
ClientConfiguration
| Property | Type | Default | Description |
|---|---|---|---|
Output |
string |
Required | Output directory for generated files |
CleanOutput |
bool |
false |
Delete existing .ts files before generation |
UseChecksum |
bool |
false |
Skip generation if checksum matches |
UseVerboseLogging |
bool |
false |
Enable detailed logging |
XmlDocumentationFile |
string |
null |
Path to XML documentation file |
UseInheritance |
bool |
false |
Generate separate types for inheritance chains |
EnumType |
EnumTypes |
None |
How to export enums (Strings, Union, Const) |
ConvertNullablePropsToOptional |
bool |
false |
Convert nullable properties to optional |
UseNamedParameters |
bool |
false |
Use object parameters instead of parameter lists |
GenericMethods |
bool |
false |
Generate methods with generic return types |
DisableTypeChecking |
bool |
true |
Add // @ts-nocheck to generated files |
TypeFormatter |
Func<ExportedType, string> |
Identity | Custom type name formatter |
AddHeaderParameter |
bool |
false |
Include header parameter in methods |
AddEventCallback |
bool |
false |
Include XHR event callback parameter |
AddReturnXhrFlag |
bool |
false |
Include flag to return XHR object on error |
LoggingCallback |
Action<string> |
null |
Custom logging callback |
Indentation |
Indentation |
4 spaces | Indentation settings |
IFormFileType |
string |
"Blob" |
TypeScript type for IFormFile |
DefaultFileResultBehavior |
FileResultBehavior |
Redirect |
Behavior for file result methods |
Includes |
HashSet<string> |
Empty | Force include types (supports wildcards, e.g. MyNamespace.*) |
Example Configuration
ClientBuilder.Build(new ClientConfiguration
{
Output = "wwwroot/api",
CleanOutput = true,
UseChecksum = true,
XmlDocumentationFile = "bin/Debug/net8.0/MyApi.xml",
EnumType = EnumTypes.Strings | EnumTypes.Union,
ConvertNullablePropsToOptional = true,
UseNamedParameters = true,
Indentation = new Indentation
{
Character = ' ',
Size = 2
},
LoggingCallback = message => Console.WriteLine($"[ClientBuilder] {message}")
});
Attributes
Controller & Method Attributes
[ClientBuilderAttribute]
Configure client generation at controller or method level using ClientBuilderSettings flags:
| Flag | Description |
|---|---|
AddHeader |
Add header parameter to generated methods |
AddEventCallback |
Add XHR event callback parameter |
AddReturnXhrFlag |
Add flag to return XHR object on error |
OmitHeader |
Omit header parameter (overrides controller-level setting) |
OmitEventCallback |
Omit event callback (overrides controller-level setting) |
OmitReturnXhrFlag |
Omit return XHR flag (overrides controller-level setting) |
[ClientBuilder(ClientBuilderSettings.AddHeader | ClientBuilderSettings.AddEventCallback)]
public class MyController : ControllerBase
{
[ClientBuilder(ClientBuilderSettings.OmitHeader)]
public IActionResult MyMethod() { }
}
[ClientBuilderIgnore]
Exclude controllers, methods, properties, or parameters from generation:
[ClientBuilderIgnore]
public class InternalController : ControllerBase { }
[ClientBuilderMethodName]
Override the generated method name:
[ClientBuilderMethodName("fetchWeather")]
public IActionResult GetWeather() { }
[ClientBuilderReturnsUrl] / [ClientBuilderRedirect]
Control file download behavior (GET requests only):
[ClientBuilderReturnsUrl]
public FileResult DownloadFile() { }
[AddQueryParameter]
Add query parameters without declaring them in the method:
[AddQueryParameter("version", typeof(int))]
public IActionResult Get() { }
Type Attributes
[UnionType]
Generate string union types:
public class Model
{
[UnionType("success", "error", "pending")]
public string Status { get; set; }
}
Generates: status: "success" | "error" | "pending"
[KeyOf]
Generate keyof types:
public class Model
{
[KeyOf(typeof(User))]
public string Field { get; set; }
}
Generates: field: keyof User
[TypedIdOf]
Override property type:
public class Model
{
[TypedIdOf(typeof(User))]
public int UserId { get; set; }
}
[Partial]
Generate Partial<T> types. You can optionally specify a type override:
public IActionResult Update([Partial] User user) { }
// With explicit type
public IActionResult Patch([Partial(typeof(UserDto))] User user) { }
[Nullable] / [Optional]
Mark properties as nullable or optional:
public class Model
{
[Nullable]
public string Name { get; set; }
[Optional]
public int? Age { get; set; }
}
NDJSON Streaming
Return NdJsonResult<T> from a controller action to stream data as newline-delimited JSON. The generator automatically produces a TypeScript method with an onData callback instead of a regular return value.
[HttpGet("stream")]
public NdJsonResult<WeatherForecast> GetStream(int count)
{
return new NdJsonResult<WeatherForecast>(GetForecasts(count));
}
private async static IAsyncEnumerable<WeatherForecast> GetForecasts(int count)
{
for (var i = 0; i < count; i++)
{
await Task.Delay(500);
yield return new WeatherForecast { /* ... */ };
}
}
Alternatively, you can use the factory method:
return NdJsonResult.Create(GetForecasts(count));
The generated TypeScript method will look like:
getStream(count: number, onData: (data: StreamedResponse<WeatherForecast>) => void): Promise<void>
StreamedResponse<T> includes properties for the streamed data and completion status. The final chunk will have done: true to indicate the end of the stream.
The alternative way to identify that the streaming is done is by awaiting the promise returned by the method. The promise will resolve once the stream is complete, so you can use it like this:
await getStream(count, (data) => {
if (!data.done) {
console.log(data.data);
}
});
Supported Frameworks
- .NET 8.0
- .NET 9.0
- .NET 10.0
Development
Building
dotnet build
Running Sample
The Sample project demonstrates the library's features:
cd Sample
dotnet run
Check the Output directory for generated TypeScript files.
Publishing to NuGet (Internal use only)
Update version in
Source/TypeScriptClientBuilder.csproj:<BaseVersion>6.2.0</BaseVersion> <PreviewVersion>-preview.1</PreviewVersion>Preview versions will have
-preview.xsuffix, while stable releases will leave thePreviewVersionempty.Commit and push changes
Run the DevOps pipeline
Package will appear on nuget.org within a few minutes
License
MIT
Authors
Dekiru Solutions
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.2.4 | 106 | 5/13/2026 |
| 6.2.3 | 81 | 5/13/2026 |
| 6.2.2 | 85 | 5/13/2026 |
| 6.2.1 | 85 | 5/13/2026 |
| 6.2.0 | 136 | 3/11/2026 |
| 6.2.0-preview.1 | 61 | 2/13/2026 |
| 6.2.0-preview.0 | 65 | 2/13/2026 |
| 6.1.3 | 401 | 10/20/2025 |
| 6.1.2 | 204 | 10/15/2025 |
| 6.1.1 | 201 | 10/15/2025 |
| 6.1.0 | 283 | 9/19/2025 |
| 6.1.0-preview.1 | 182 | 8/13/2025 |
| 6.1.0-preview.0 | 156 | 6/3/2025 |
| 6.0.4 | 692 | 3/4/2025 |
| 6.0.3 | 207 | 3/3/2025 |
| 6.0.2 | 197 | 2/20/2025 |
| 6.0.1 | 184 | 1/30/2025 |
| 6.0.0-preview | 168 | 10/11/2024 |
| 5.0.16 | 4,436 | 8/29/2024 |
| 5.0.15 | 822 | 5/30/2024 |