@tsonic/tsbindgen
v0.1.2
Published
Generate TypeScript declarations from .NET assemblies
Maintainers
Readme
tsbindgen
A .NET tool that generates TypeScript declaration files (.d.ts) from .NET assemblies for use with the Tsonic compiler.
Overview
tsbindgen uses reflection to analyze .NET assemblies and produces TypeScript declarations that follow Tsonic's interop rules. This allows TypeScript code compiled with Tsonic to properly type-check when using .NET libraries.
Installation
Build the tool from source:
dotnet buildUsage
Basic Usage
tsbindgen <assembly-path>Example:
tsbindgen /usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/8.0.0/ref/net8.0/System.Text.Json.dll
# Creates:
# ./System.Text.Json.d.ts
# ./System.Text.Json.metadata.jsonCommand-Line Options
| Option | Short | Description | Default |
|--------|-------|-------------|---------|
| --namespaces | -n | Comma-separated list of namespaces to include | All namespaces |
| --out-dir | -o | Output directory for generated file | . (current directory) |
| --log | -l | Path to write JSON log file | None |
| --config | -c | Path to configuration JSON file | None |
Examples
Filter specific namespaces:
tsbindgen System.Text.Json.dll --namespaces System.Text.Json.SerializationSpecify output directory:
tsbindgen System.Net.Http.dll --out-dir ./declarationsGenerate with logging:
tsbindgen System.IO.dll --log build.log.jsonGenerate user library excluding BCL types:
# Step 1: Generate BCL package (once)
tsbindgen generate -d ~/dotnet/shared/Microsoft.NETCore.App/10.0.0 -o ./bcl-package
# Step 2: Generate user library, BCL types excluded
tsbindgen generate -a MyLib.dll -d ~/dotnet/.../10.0.0 \
--lib ./bcl-package -o ./my-lib-packageLibrary Mode (--lib)
When generating declarations for a user assembly that references a base library (e.g., .NET BCL), use --lib to exclude base library types from output. This produces a clean package containing only your library's types.
How it works:
- Generate base library package first (contains
metadata.json+bindings.json) - Use
--lib <base-package-path>when generating user library - tsbindgen filters: keeps types NOT in base, removes types IN base
- Validates no dangling references (LIB002 strict check)
Use case: Publishing TypeScript declarations for a .NET library without duplicating BCL type definitions.
See CLI documentation for complete details.
Generated Output
The tool generates two files for each assembly:
- TypeScript declarations (
.d.ts) - TypeScript type definitions - Metadata sidecar (
.metadata.json) - C# semantic information
TypeScript Declarations
The .d.ts file contains TypeScript declarations with:
Branded type aliases for C# numeric types:
type int = number & { __brand: "int" }; type decimal = number & { __brand: "decimal" }; // ... etcNamespace declarations matching .NET namespaces:
declare namespace System.Text.Json { class JsonSerializer { static Serialize<T>(value: T): string; } }Proper type mappings:
System.String→stringSystem.Int32→intSystem.Boolean→booleanTask<T>→Promise<T>T[]→ReadonlyArray<T>List<T>→List<T>Nullable<T>→T | null
Metadata Sidecar Files
The .metadata.json file contains C# semantic information that TypeScript cannot express. This enables the Tsonic compiler to generate correct C# code, particularly for:
- Virtual/override methods - Required to correctly override base class methods
- Abstract classes/methods - Required to properly extend abstract types
- Sealed classes/methods - Prevents invalid inheritance
- Static classes - Type-level restrictions
- Struct vs Class - Value vs reference type semantics
- Method accessibility - Public, protected, private, internal modifiers
Example Structure
{
"assemblyName": "System.Text.Json",
"assemblyVersion": "10.0.0.0",
"types": {
"System.Text.Json.JsonSerializer": {
"kind": "class",
"isAbstract": true,
"isSealed": false,
"isStatic": false,
"baseType": null,
"interfaces": [],
"members": {
"Serialize<T>(T)": {
"kind": "method",
"isVirtual": false,
"isAbstract": false,
"isSealed": false,
"isOverride": false,
"isStatic": true,
"accessibility": "public"
},
"Deserialize<T>(string)": {
"kind": "method",
"isVirtual": false,
"isAbstract": false,
"isSealed": false,
"isOverride": false,
"isStatic": true,
"accessibility": "public"
}
}
}
}
}Metadata Fields
Type-level fields:
kind:"class","struct","interface", or"enum"isAbstract: True for abstract classes (excluding interfaces)isSealed: True for sealed classes (excluding value types and enums)isStatic: True for static classesbaseType: Full name of base class (if any)interfaces: Array of implemented interface namesmembers: Dictionary of member metadata keyed by signature
Member-level fields:
kind:"method","property", or"constructor"isVirtual: True if method can be overriddenisAbstract: True for abstract methodsisSealed: True if method prevents further overridingisOverride: True if method overrides a base methodisStatic: True for static membersaccessibility:"public","protected","private","internal", etc.
Signature format:
- Methods:
MethodName(Type1,Type2,...)using C# type names - Properties:
PropertyName - Constructors:
ctor(Type1,Type2,...)
Configuration File
You can provide a JSON configuration file to customize behavior:
{
"skipNamespaces": ["System.Internal"],
"typeRenames": {
"System.OldType": "NewType"
},
"skipMembers": [
"System.String::InternalMethod"
]
}Usage:
tsbindgen Assembly.dll --config config.jsonLog Output
When using --log, a JSON file is generated with:
{
"timestamp": "2025-11-01T13:03:38Z",
"namespaces": ["System.Text.Json"],
"typeCounts": {
"classes": 40,
"interfaces": 5,
"enums": 10,
"total": 55
},
"warnings": []
}Type Mapping Rules
The tool follows Tsonic's type mapping specification:
- Classes → TypeScript classes
- Interfaces → TypeScript interfaces
- Enums → TypeScript enums
- Structs → TypeScript classes
- Static methods →
staticmethods - Properties → TypeScript properties (with
readonlywhen appropriate) - Generic types → TypeScript generics
<T> - Optional parameters →
param?: Type - Params arrays →
...values: ReadonlyArray<T>
Excluded Members
The tool automatically skips:
- Private and internal members
- Compiler-generated types
- Common Object methods (
Equals,GetHashCode,ToString,GetType,ReferenceEquals) - Special-name members (property accessors, backing fields)
Reserved Keyword Escaping
Parameter names that conflict with TypeScript/JavaScript reserved keywords are automatically escaped by prefixing them with an underscore. This prevents syntax errors in the generated declarations.
Escaped keywords include:
- Control flow:
break,case,catch,continue,default,do,else,finally,for,if,return,switch,throw,try,while - Declarations:
class,const,enum,export,extends,function,import,let,var,void - Modifiers:
async,await,implements,interface,package,private,protected,public,static,yield - Special identifiers:
arguments,eval,this,super,new,typeof,instanceof,delete,debugger,with,in
Example:
// C# method signature
public static LoopExpression Loop(Expression body, LabelTarget break, LabelTarget continue)
// Generated TypeScript
static Loop(body: Expression, _break: LabelTarget, _continue: LabelTarget): LoopExpression;This ensures that all generated .d.ts files are valid TypeScript and can be parsed by the TypeScript compiler without syntax errors.
Testing & Validation
The project includes comprehensive test scripts to ensure correctness and prevent regressions.
Running All Tests
# TypeScript syntax validation
npm install # First time only
npm run validate
# Regression guards (run all)
./scripts/test-determinism.sh # Deterministic output
./scripts/test-strict-mode.sh # Strict mode compliance
./scripts/test-surface-manifest.sh # Surface baseline guard
./scripts/test-lib.sh # Library mode (--lib)TypeScript Validation
Ensures all generated .d.ts files are syntactically valid TypeScript:
npm run validateThis script:
- Regenerates all 38 BCL assemblies to a temporary directory
- Creates an
index.d.tswith triple-slash references - Runs the TypeScript compiler to validate all declarations
- Reports syntax errors (TS1xxx), duplicate type errors (TS6200), and semantic errors (TS2xxx)
Success criteria:
- ✅ Zero syntax errors (TS1xxx) - All output is valid TypeScript
- ⚠️ Semantic errors acceptable - TS2xxx errors are expected (known limitations)
Example output:
✓ VALIDATION PASSED
All 38 assemblies generated successfully
All metadata files present
✓ No TypeScript syntax errors (TS1xxx)
Error breakdown:
- Syntax errors (TS1xxx): 0 ✓
- Duplicate types (TS6200): 0 (expected)
- Semantic errors (TS2xxx): 1 (expected - missing cross-assembly refs)Regression Guards
Determinism Test (test-determinism.sh)
Ensures tsbindgen produces identical output across runs:
./scripts/test-determinism.shWhat it tests:
- Same input → same output (bit-for-bit identical)
- No nondeterministic ordering or formatting
- Critical for reproducible builds and diffing
Strict Mode Test (test-strict-mode.sh)
Verifies strict mode compliance and performance baseline:
./scripts/test-strict-mode.shWhat it tests:
- No diagnostics with
--strictflag - Performance doesn't regress beyond baseline
Surface Baseline Test (test-surface-manifest.sh)
Guards against accidental removal of public API surface:
./scripts/test-surface-manifest.shWhat it tests:
- Type count matches baseline (prevents deletions)
- Member count matches baseline (prevents deletions)
- Intentional changes require baseline update
Library Mode Test (test-lib.sh)
Validates --lib mode filters base library types correctly:
./scripts/test-lib.shWhat it tests:
- BCL package generation succeeds
- User library builds successfully
- Full generation includes both user + BCL types
--libfiltered generation includes ONLY user types- No LIB001-003 validation errors
- BCL namespaces correctly excluded from filtered output
- User namespaces correctly included in filtered output
Expected result:
✓ LIBRARY MODE FULLY VERIFIED
Summary:
✓ BCL generation succeeded (130 namespaces)
✓ User library build succeeded
✓ Full generation: 131 namespaces (user + BCL)
✓ Filtered generation: 1 namespaces (user only)
✓ BCL types correctly excluded via --lib
✓ User types (MyCompany.Utils) correctly included
✓ No LIB001-003 validation errors
✓ Strict mode passesDevelopment
Project Structure
tsbindgen/
├── Src/
│ ├── Program.cs # CLI entry point
│ ├── AssemblyProcessor.cs # Reflection and type/metadata extraction
│ ├── TypeMapper.cs # C# to TypeScript type mapping
│ ├── DeclarationRenderer.cs # TypeScript output generation
│ ├── TypeInfo.cs # Data structures for declarations
│ ├── MetadataModel.cs # Data structures for metadata
│ ├── SignatureFormatter.cs # Method/property signature formatting
│ ├── MetadataWriter.cs # JSON metadata serialization
│ ├── GeneratorConfig.cs # Configuration support
│ └── GenerationLogger.cs # Logging functionality
├── Scripts/
│ └── validate.js # Full validation script
├── package.json # npm scripts (validate)
└── README.mdBuilding
dotnet buildRunning
dotnet run --project Src -- <assembly-path> [options]Related Documentation
License
See LICENSE file for details.
