this file is generated with copilot
- Project Overview
- Architecture
- Project Structure
- Core Components
- Key Models
- Generation Modes
- Usage Guide
- Development Guide
CsharpToTypeScriptConverter is a .NET 9.0 code generation library that automatically converts C# types (classes, interfaces, enums) to equivalent TypeScript code. This tool enables seamless synchronization of type definitions between a C# backend API and a TypeScript frontend client.
- Converts C# classes, interfaces, and enums to TypeScript
- Supports generic types and nested generics
- Generates either a single file or multiple separated files
- Preserves XML documentation from C# code
- Supports command patterns with
ICommand<T>andIRequestCommandinterfaces - Generates type metadata for JSON deserialization
- Framework: .NET 9.0
- Package Version: 0.9.1
This library is designed for communication between an ASP.NET API and a TypeScript client using a command-based architecture. It ensures type safety and consistency across language boundaries while maintaining domain language clarity.
CsharpToTypeScriptConverter
└── TypeScriptGenerator (Entry Point)
├── OneFileGenerator (Single TypeScript file output)
│ ├── OneFileGeneratorWithMetaData
│ └── Templates/OneFile/TypesScriptGenerator
│
└── SeparatedFilesGenerator (Multiple TypeScript files)
├── SeparatedFilesGeneratorWithMetaData
├── SeparatedFilesGeneratorWithRenderedTypes
├── BuildedSeparatedFiles
└── Templates/SeparatedFiles/*
- Builder Pattern: Generator classes build the output step-by-step
- Template Method Pattern: T4 templates (
.ttfiles) define code generation templates - Strategy Pattern: Different generation strategies (OneFile vs SeparatedFiles)
- Reflection: Uses .NET Reflection to analyze C# types and extract metadata
- Visitor Pattern: Processes type hierarchies to collect and transform data
D:\GIT\CsharpToTypeScriptConverter\
├── src\
│ ├── CsharpToTypeScriptConverter.Generator\
│ │ ├── Generator.cs (Main entry point)
│ │ ├── Generators\
│ │ │ └── TypeScript\
│ │ │ ├── TypeScriptGenerator.cs
│ │ │ ├── OneFile\
│ │ │ │ ├── OneFileGenerator.cs
│ │ │ │ └── OneFileGeneratorWithMetaData.cs
│ │ │ └── SeparatedFiles\
│ │ │ ├── SeparatedFilesGenerator.cs
│ │ │ ├── SeparatedFilesGeneratorWithMetaData.cs
│ │ │ ├── SeparatedFilesGeneratorWithRenderedTypes.cs
│ │ │ └── BuildedSeparatedFiles.cs
│ │ ├── Models\
│ │ │ ├── GeneratorType.cs
│ │ │ ├── GeneratorMember.cs
│ │ │ ├── GeneratorTypeKind.cs
│ │ │ ├── BuildFile.cs
│ │ │ ├── BuildFileType.cs
│ │ │ ├── FileMetadata.cs
│ │ │ ├── FileMetadataType.cs
│ │ │ └── TypeScriptImportDependency.cs
│ │ ├── Templates\
│ │ │ ├── SeparatedFiles\
│ │ │ │ ├── Commands\
│ │ │ │ ├── ComplexTypes\
│ │ │ │ ├── CommandInterface\
│ │ │ │ ├── Enumerations\
│ │ │ │ ├── CodeGenerationWarning\
│ │ │ │ └── TypeScriptImports\
│ │ │ └── OneFIle\
│ │ ├── Tools\
│ │ │ ├── DocumentationTools.cs
│ │ │ ├── MetadataHelper.cs
│ │ │ ├── TypeDependencyResolver.cs
│ │ │ └── TypeFileGenerator.cs
│ │ └── TypeScriptRequestCommandsGenerator.csproj
│ │
│ └── CsharpToTypeScriptConverter.Tests\
│ ├── OneFileGeneratorTests.cs
│ ├── SeparatedFilesGeneratorTests.cs
│ ├── TestDefinitionsData.cs
│ └── CsharpToTypeScriptConverter.Tests.csproj
│
├── README.md
├── LICENSE
└── (Other solution files)
Generators/
- Contains all code generation logic organized by output strategy
Templates/
- T4 text templates (
.ttfiles) that define TypeScript code generation templates - Auto-generated
.csfiles from templates using TextTemplatingFilePreprocessor - Organized by generation strategy and type category
Models/
- Data transfer objects representing C# and TypeScript metadata
- Used internally by generators to transform type information
Tools/
- Utility classes for reflection, documentation parsing, and type resolution
DocumentationTools: Extracts XML documentation from .NET assembliesMetadataHelper: Converts C# types to GeneratorType metadataTypeDependencyResolver: Resolves type dependencies for import generationTypeFileGenerator: Creates individual TypeScript files
Tests/
- Unit tests validating generator output for both strategies
File: Generator.cs
public class Generator
{
public TypeScriptGenerator TypeScript()
{
return new TypeScriptGenerator();
}
}Purpose: Main entry point for the library. Provides fluent API access to TypeScript generation capabilities.
Usage:
var generator = new Generator();
var tsGenerator = generator.TypeScript();File: Generators/TypeScript/TypeScriptGenerator.cs
Purpose: Facade class providing access to different generation strategies.
Methods:
OneFile(): ReturnsOneFileGeneratorfor single-file outputSeparatedFiles(): ReturnsSeparatedFilesGeneratorfor multi-file output
File: Generators/TypeScript/OneFile/OneFileGenerator.cs
Purpose: Generates all TypeScript types into a single .ts file
Key Methods:
- Configures generator settings
- Manages type metadata collection
- Transforms C# types to TypeScript using templates
Related Classes:
OneFileGeneratorWithMetaData: Extended version with metadata support
File: Generators/TypeScript/SeparatedFiles/SeparatedFilesGenerator.cs
Purpose: Generates each TypeScript type into separate .ts files
Key Features:
- Organizes output by type category (commands, enums, complex types, interfaces)
- Manages import dependencies between files
- Generates warning comments in generated files
Related Classes:
SeparatedFilesGeneratorWithMetaData: Metadata versionSeparatedFilesGeneratorWithRenderedTypes: Handles pre-rendered typesBuildedSeparatedFiles: Container for built file structure
File: Tools/DocumentationTools.cs
Purpose: Parses XML documentation from .NET assemblies and extracts developer-written documentation
Key Members:
LoadedXmlDocumentation: Dictionary storing parsed XML docs by member keyLoadedAssemblies: Set of assemblies with loaded documentationLoadXmlDocumentation(Assembly): Loads XML docs from assemblyGetDocumentation(Type|PropertyInfo|ParameterInfo): Retrieves documentation for specific membersOnlyDocumentationText(): Extracts clean text from XML doc markup
Key Methods:
GetDocumentation(this MemberInfo): Route to appropriate documentation getter based on member typeXmlDocumentationKeyHelper(): Formats XML documentation keys for lookupLoadXmlDocumentation(string): Parses raw XML documentation content
File: Tools/MetadataHelper.cs
Purpose: Converts C# reflection data to GeneratorType metadata used by templates
Key Responsibilities:
- Extract type information from C# types
- Identify command types and return types
- Resolve generic type parameters
- Build member metadata for properties and fields
- Track used types for dependency resolution
File: Tools/TypeDependencyResolver.cs
Purpose: Analyzes type dependencies and generates import statements for TypeScript
Key Responsibilities:
- Track which types depend on other types
- Generate proper import paths between files
- Handle circular dependency detection
- Resolve type names to file locations
File: Tools/TypeFileGenerator.cs
Purpose: Creates individual TypeScript files with proper content
Key Responsibilities:
- Apply templates to generate file content
- Handle file naming conventions
- Manage file system operations
- Organize files into directory structure
File: Models/GeneratorType.cs
Represents a C# type converted to TypeScript metadata.
public class GeneratorType
{
public string Name { get; set; } // TypeScript type name
public string TypeNameForJsonDeserialization { get; set; } // Type reference for JSON
public string ReturnTypeName { get; set; } // For commands: return type
public GeneratorTypeKind Kind { get; set; } // Class, Enum, Interface, etc.
public IEnumerable<GeneratorMember> Members { get; set; } // Properties/fields
public string[] ImplementsInterfaceTypeNames { get; set; } // Implemented interfaces
public string[] Documentation { get; set; } // XML docs converted to text
public string GeneratedCode { get; set; } // Generated TypeScript code
public Type Type { get; set; } // Original C# type
}File: Models/GeneratorMember.cs
Represents a member (property/field) of a type.
Properties:
Name: Member nameTypeName: TypeScript type nameKind: Member kind (property, field, etc.)IsOptional: Whether member is nullable/optionalDocumentation: XML documentation
File: Models/GeneratorTypeKind.cs
Enum distinguishing different type categories:
Class: Regular C# classEnum: EnumerationInterface: Interface definitionCommandWithGenericReturnType: Command withICommand<T>
File: Models/BuildFile.cs
Represents a generated TypeScript file ready for output.
Properties:
FileName: Output filenameFileType: Category of file (Command, Enum, ComplexType, Interface, etc.)FileContent: Generated TypeScript codeFilePath: Full path where file should be written
File: Models/FileMetadata.cs
Metadata about a TypeScript file for tracking and organization.
File: Models/TypeScriptImportDependency.cs
Represents an import statement needed between TypeScript files.
Properties:
- Source type
- Target type
- Import path
- Import statements to generate
Use Case: When you want all TypeScript types in a single .ts file
Entry Point: TypeScriptGenerator.OneFile()
Workflow:
- Collect all C# types to convert
- Apply OneFileGenerator template to all types at once
- Include all imports at the top of the file
- Write single output file
Output Structure:
// Single file with all interfaces, classes, and enums
export interface ICommand<T> { _?: T }
export class MyCommand implements ICommand<boolean> { ... }
export enum MyEnum { ... }Advantages:
- Simple structure
- Minimal file management
- Good for smaller projects
Use Case: When you want organized, modular TypeScript files
Entry Point: TypeScriptGenerator.SeparatedFiles()
Workflow:
- Collect all C# types to convert
- Categorize types by kind (commands, enums, complex types, interfaces)
- Generate individual files for each type category or type
- Calculate import dependencies
- Generate import statements for each file
- Write individual files to organized directory structure
Output Structure:
output/
├── commands/
│ ├── index.ts (barrel export)
│ ├── myCommand.ts
│ └── anotherCommand.ts
├── enums/
│ ├── index.ts
│ └── myEnum.ts
├── types/
│ ├── index.ts
│ └── complexType.ts
├── interfaces/
│ ├── index.ts
│ └── iCommand.ts
└── generationWarning.ts
Advantages:
- Clear organization by type
- Easier to maintain and navigate
- Better for large projects
- Barrel exports for cleaner imports
Install-Package CSharpToTypeScriptConverter// Command interface (generic return type)
public interface ICommand<T>;
// Request command marker interface
public interface IRequestCommand;
// Example command
public class ChangeUserRoleRequestCommand : IRequestCommand, ICommand<bool>
{
public string UserId { get; set; }
public UserRoles NewRole { get; set; }
}
// Example enum
public enum UserRoles
{
User,
Admin
}using TypeScriptRequestCommandsGenerator;
using TypeScriptRequestCommandsGenerator.Tools;
// Get all exported types from assembly
var exportedTypes = typeof(UserRoles).Assembly.ExportedTypes;
// Define interfaces to search for
var requestCommandType = typeof(IRequestCommand);
var commandReturnType = typeof(ICommand<>);
// Create settings
var usedTypes = new Dictionary<string, Type>();
TypesScriptGenerator.Settings.RequestCommandInterfaceName = "ICommand";
// Get metadata for types
var typesMetadata = MetadataHelper.GetGeneratorTypesMetadata(
exportedTypes,
requestCommandType,
commandReturnType,
usedTypes
);
// Handle types that weren't automatically included
var notGeneratedTypes = usedTypes
.Where(ut => typesMetadata.All(tm => tm.Name != ut.Key))
.ToDictionary();
if (notGeneratedTypes.Count > 0)
{
typesMetadata.AddRange(
MetadataHelper.GetGeneratorTypesForUsedTypes(notGeneratedTypes)
);
}
// Generate TypeScript
var generator = new Generator();
var oneFileGen = generator.TypeScript().OneFile();
var transformedText = oneFileGen.Generate(typesMetadata.ToArray());
// Write to file
File.WriteAllText("./typeScriptTypes.ts", transformedText);// ... (setup same as above until generation)
// Generate separated files
var generator = new Generator();
var separatedGen = generator.TypeScript().SeparatedFiles();
var builtFiles = separatedGen.Generate(typesMetadata.ToArray());
// Write files
foreach (var file in builtFiles.BuildFiles)
{
var fullPath = Path.Combine("./output", file.FilePath);
Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
File.WriteAllText(fullPath, file.FileContent);
}Input C# Code:
public class ChangeUserRoleRequestCommand : IRequestCommand, ICommand<bool>
{
/// <summary>User identifier to change role for</summary>
public string UserId { get; set; }
/// <summary>New role to assign</summary>
public UserRoles NewRole { get; set; }
}
public enum UserRoles { User = 0, Admin = 1 }
public interface ICommand<T> { _?: T }Output TypeScript:
/**
* User identifier to change role for
*/
export class ChangeUserRoleRequestCommand implements ICommand<boolean> {
private readonly $type? = ".ChangeUserRole, CsharpToTypeScriptConverter.Tests";
public _?: boolean;
public userId?: string;
public newRole?: UserRoles;
}
export enum UserRoles {
User = 0,
Admin = 1,
}
export interface ICommand<T> {
_?: T;
}T4 templates control code generation. To add support for a new type of output:
- Create template file (e.g.,
Templates/SeparatedFiles/MyType/MyTypeGenerator.tt) - Update project file (
.csproj) to register the template:<None Update="Templates/SeparatedFiles/MyType/MyTypeGenerator.tt"> <LastGenOutput>MyTypeGenerator.cs</LastGenOutput> <Generator>TextTemplatingFilePreprocessor</Generator> </None>
- Implement template logic in the
.ttfile - Create extension class (e.g.,
MyTypeGeneratorExt.cs) for helper methods - Integrate into generator by calling template from generator class
To customize type metadata extraction:
- Add new static method to
MetadataHelperclass - Implement reflection logic to extract desired metadata
- Return
GeneratorType[]array with custom data - Call from generator before template processing
To add documentation to generated TypeScript:
- Ensure C# types have XML documentation (
/// <summary>...) - Use
DocumentationTools.LoadXmlDocumentation(assembly)to load docs - Extract docs via
DocumentationTools.GetDocumentation(memberInfo) - Pass documentation strings to template
- Template includes docs in generated code
Use unit tests to validate generation:
Key Test Classes:
OneFileGeneratorTests.cs: Tests single-file generationSeparatedFilesGeneratorTests.cs: Tests multi-file generationTestDefinitionsData.cs: Test data and expected outputs
Testing Pattern:
- Define test C# types
- Generate TypeScript
- Assert generated code matches expected output
- Verify imports and dependencies
Build:
dotnet buildRun Tests:
dotnet testCreate NuGet Package:
- Project is configured with
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> - Build creates
.nupkgfile automatically - Package metadata in
.csproj:- Version: 0.9.1
- Description: Generates classes, enums, interfaces from C# to TypeScript
- Repository: https://github.com/a-t-k/CsharpToTypeScriptConverter
- Decision: Use .NET Reflection instead of parsing source code
- Rationale: Works with compiled assemblies, handles complex scenarios
- Trade-off: Requires compiled types, not source-only
- Decision: Use T4 text templates instead of string builders
- Rationale: Separate concerns (template design vs logic), cleaner code
- Trade-off: Need template preprocessing in build
- Decision: Support both one-file and separated-file modes
- Rationale: Different projects have different needs
- Trade-off: More code to maintain
- Decision: Special handling for
ICommand<T>andIRequestCommand - Rationale: Command pattern is primary use case
- Trade-off: Less flexible than generic interface support
- Decision: Track used types and resolve them on demand
- Rationale: Handle transitive dependencies efficiently
- Trade-off: Multiple passes required sometimes
Cause: XML documentation file (.xml) not found in assembly directory
Solution:
- Ensure C# project has
<GenerateDocumentationFile>true</GenerateDocumentationFile> - Copy
.xmlfile to same directory as assembly - Load documentation before generating types
Cause: Type doesn't implement required interface (IRequestCommand/ICommand) Solution:
- Check type implements required interfaces
- Verify assembly is passed to generator
- Check type visibility (must be public)
Cause: Dependency not tracked by TypeDependencyResolver Solution:
- Ensure all used types are in generated metadata
- Call
GetGeneratorTypesForUsedTypes()for transitive dependencies - Verify import path calculation in TypeDependencyResolver
- Reflection Impact: Type analysis uses reflection; minimize assembly loads
- Caching: XML documentation is cached in
LoadedXmlDocumentation - Memory: Large projects may benefit from separated files generation
- File I/O: Batch file writes for performance
Potential improvements for future versions:
- Support more generic interface patterns
- Custom attribute-based generation control
- TypeScript strict mode optimizations
- Angular/React specific output modes
- JSON schema integration
- Performance optimizations for large codebases
- Repository: https://github.com/a-t-k/CsharpToTypeScriptConverter
- NuGet Package: https://www.nuget.org/packages/TypeScriptRequestCommandsGenerator
- .NET Framework: .NET 9.0
- Related Patterns: CQRS, Event Sourcing, Domain-Driven Design