Skip to content
This repository was archived by the owner on Jun 18, 2026. It is now read-only.

tsoniclang/dotnet-bindgen

Repository files navigation

dotnet-bindgen

TypeScript type declaration generator for .NET assemblies

dotnet-bindgen generates TypeScript declaration files (.d.ts) from .NET assemblies using reflection. It creates fully-typed, IDE-friendly TypeScript definitions that map the entire .NET Base Class Library (BCL) to TypeScript.

Features

  • Complete BCL coverage - Generates declarations for all 130 BCL namespaces, 4,047 types
  • Zero TypeScript errors - Output validates cleanly with tsc --strict
  • Nullable reference types - NRT support for output positions (returns, properties, fields)
  • CLR primitives - Numeric type aliases (int, long, decimal, etc.) via @tsonic/core
  • Broad CLR object safety - System.Object projects to TypeScript unknown, and value-type constraints project to NonNullable<unknown>
  • CLR-faithful names - No casing transforms; member names match the CLR surface
  • Generic type preservation - Full generic type parameter support with constraints
  • Unified bindings manifest - CLR-specific information lives in <Namespace>/bindings.json (no metadata sidecars)
  • Library mode - Generate only your assembly's types, importing BCL types from pre-existing packages
  • Namespace mapping - Customize output directory names with --namespace-map
  • Class flattening - Export static class methods as top-level functions with --flatten-class

Installation

Via npm (recommended)

npm install dotnet-bindgen
# or
npm install @tsonic/dotnet-bindgen

Requires .NET 10 runtime installed.

From source

git clone https://github.com/tsoniclang/dotnet-bindgen
cd dotnet-bindgen
dotnet build src/DotnetBindgen/DotnetBindgen.csproj

Quick Start

Generate BCL declarations

DOTNET_RUNTIME=$(dirname "$(dotnet --list-runtimes | awk '/Microsoft.NETCore.App 10\\./ { print $3; exit }')")

# Via npm
npx dotnet-bindgen generate -d "$DOTNET_RUNTIME" -o ./output

# Via dotnet (from source)
dotnet run --project src/DotnetBindgen/DotnetBindgen.csproj -- \
  generate -d "$DOTNET_RUNTIME" -o ./output

Generate for a custom assembly

# Via npm
npx dotnet-bindgen generate -a ./MyLibrary.dll -d $DOTNET_RUNTIME -o ./output

# Via dotnet (from source)
dotnet run --project src/DotnetBindgen/DotnetBindgen.csproj -- \
  generate -a ./MyLibrary.dll -d $DOTNET_RUNTIME -o ./output

Library mode (exclude BCL types)

# First, generate BCL types
npx dotnet-bindgen generate -d $DOTNET_RUNTIME -o ./bcl-types

# Then generate your library, importing BCL from the pre-existing package
npx dotnet-bindgen generate -a ./MyLibrary.dll -d $DOTNET_RUNTIME -o ./my-lib --lib ./bcl-types

If you provide multiple --lib packages and the same CLR type exists in more than one of them, dotnet-bindgen will hard-error because it cannot safely choose an import source. In rare cases where this is expected, you can provide explicit per-type overrides:

npx dotnet-bindgen generate -a ./MyLibrary.dll -d $DOTNET_RUNTIME -o ./my-lib \
  --lib ./efcore-types \
  --lib ./efcore-abstractions \
  --lib-type-override "Microsoft.EntityFrameworkCore.DbContext=@tsonic/efcore"

CLI Reference

Commands

Command Description
generate Generate TypeScript declarations from .NET assemblies
resolve-closure Resolve transitive assembly dependency closure (JSON)

Generate Options

Option Short Description Default
--assembly -a Path to assembly file(s) to process -
--assembly-dir -d Directory containing .NET runtime assemblies -
--ref-dir - Additional directory to search for referenced assemblies (repeatable) -
--out-dir -o Output directory for generated files out
--namespaces -n Namespace filter (reserved; currently ignored) (all)
--lib - Path to pre-existing dotnet-bindgen package (repeatable) -
--lib-type-override - Override owning package for a CLR type when merging multiple --lib packages (repeatable; ClrFullName=packageName) -
--namespace-map - Map CLR namespace to output name (repeatable) -
--flatten-class - Flatten static class to top-level exports (repeatable) -
--verbose -v Enable detailed progress output false
--logs - Enable specific log categories (repeatable; space-separated values) -
--strict - Enable strict mode validation false

resolve-closure

Machine-readable dependency resolution for one or more seed assemblies. Useful for:

  • Debugging missing dependencies before generation
  • Tooling integrations (e.g. build systems) that need deterministic closure resolution
  • Source builds and tests that should resolve the installed .NET runtime without assuming a fixed install directory
# Standard SDK/runtime installs usually work with no extra ref dirs
npx dotnet-bindgen resolve-closure -a ./MyLibrary.dll

# Add extra directories only when dependencies live outside the runtime closure
npx dotnet-bindgen resolve-closure \
  -a ./MyLibrary.dll \
  --ref-dir ./libs

.NET runtime discovery

Repo-local test scripts discover the installed Microsoft.NETCore.App runtime through dotnet --list-runtimes. Set DOTNET_RUNTIME to override the runtime assembly directory explicitly.

Surface-manifest validation is tied to the runtime assembly version. If the runtime version and baseline manifest do not match, the validator reports that version mismatch directly.

Examples

# Generate a custom assembly
npx dotnet-bindgen generate -a ./MyLibrary.dll -o ./out

# Add extra directories when dependencies live outside the runtime closure
npx dotnet-bindgen generate -a ./MyLibrary.dll -o ./out \
  --ref-dir ./libs

# Verbose output with specific log categories
npx dotnet-bindgen generate -d $DOTNET_RUNTIME -o ./out -v --logs ImportPlanner FacadeEmitter

# Strict mode (additional validation)
npx dotnet-bindgen generate -d $DOTNET_RUNTIME -o ./out --strict

Output Structure

dotnet-bindgen emits a flat ESM facade per namespace plus a per-namespace directory for internals:

output/
├── families.json                      # Multi-arity family index
├── __internal/extensions/index.d.ts   # Extension method buckets
├── System.d.ts                        # Facade (public API)
├── System.js                          # Runtime stub (throws)
├── System/
│   ├── bindings.json
│   └── internal/index.d.ts            # Full declarations
├── System.Collections.Generic.d.ts
├── System.Collections.Generic.js
└── System.Collections.Generic/
    ├── bindings.json
    └── internal/index.d.ts

Publishing Bindings Packages (dist/ + npm exports)

When you publish bindings for your own assemblies (or generate them inside an npm workspace), you can keep generated artifacts out of git by writing them under dist/ and exposing the facades via npm exports:

dist/tsonic/bindings/
  Acme.Domain.js
  Acme.Domain.d.ts
  Acme.Domain/
    bindings.json
    internal/index.d.ts

package.json:

{
  "type": "module",
  "exports": {
    "./package.json": "./package.json",
    "./*.js": {
      "types": "./dist/tsonic/bindings/*.d.ts",
      "default": "./dist/tsonic/bindings/*.js"
    }
  }
}

Consumers can then import CLR namespaces ergonomically:

import { TodoItem } from "@acme/domain/Acme.Domain.js";

Tsonic resolves the import using Node’s module resolution (including exports) and locates the nearest bindings.json for CLR discovery.

Output Files

File Description
<Namespace>.d.ts Public facade with curated exports and friendly aliases
<Namespace>.js Module stub that throws if executed in Node
<Namespace>/internal/index.d.ts Full type declarations ($instance + __views)
<Namespace>/bindings.json CLR bindings manifest for the Tsonic compiler (names + CLR semantics)

Extension Methods (C# using Semantics)

dotnet-bindgen collects C# extension methods into bucket helper types under __internal/extensions/index.d.ts and re-exports a per-namespace helper from each facade:

// System.Linq.d.ts
export type { ExtensionMethods_System_Linq as ExtensionMethods } from "./__internal/extensions/index.js";

Use the helper as a type-level “using” wrapper:

import type { ExtensionMethods as Linq } from "@tsonic/dotnet/System.Linq.js";
import type { IEnumerable } from "@tsonic/dotnet/System.Collections.Generic.js";

type LinqSeq<T> = Linq<IEnumerable<T>>;

declare const xs: LinqSeq<number>;
xs.Where((x) => x > 0).Select((x) => x * 2);

Type Mapping

Primitive Types

CLR primitive types map to type aliases from @tsonic/core:

CLR Type TypeScript Type
System.Int32 int (alias for number)
System.Int64 long (alias for number)
System.Single float (alias for number)
System.Double double (alias for number)
System.Decimal decimal (alias for number)
System.Byte byte (alias for number)
System.Boolean bool (branded)
System.String string
System.Char char (branded)
System.Object unknown
System.ValueType constraint NonNullable<unknown>

unknown is intentional: it is the TypeScript boundary type for a broad CLR object slot. Generated packages do not import a package-specific catch-all value type for System.Object; callers narrow or adapt broad values explicitly.

Generic Types

Generic types use underscore suffix for arity:

CLR Type TypeScript Type
List<T> List_1<T>
Dictionary<TKey, TValue> Dictionary_2<TKey, TValue>
Func<T, TResult> Func_2<T, TResult>

Friendly aliases are also exported:

// Both work:
import { List_1 } from "@tsonic/dotnet/System.Collections.Generic.js";
import { List } from "@tsonic/dotnet/System.Collections.Generic.js";  // Friendly alias

Type Kind Mapping

CLR Kind TypeScript Pattern
Class interface + const (instance + static sides)
Struct interface + const
Interface interface
Enum const enum
Delegate type (function signature + CLR type intersection)
Static class abstract class (static methods only)

Naming

dotnet-bindgen emits CLR-faithful names (no casing transforms).

Testing

# Run all regression tests
bash test/scripts/run-all.sh

# Run validation (TypeScript compilation check)
node test/validate/validate.js

# Individual tests
bash test/scripts/test-strict-mode.sh
bash test/scripts/test-determinism.sh
bash test/scripts/test-surface-manifest.sh
bash test/scripts/test-lib.sh

Development

Project Structure

dotnet-bindgen/
├── src/DotnetBindgen/
│   ├── Cli/                 # Command-line interface
│   ├── Load/                # Assembly loading and reflection
│   ├── Model/               # Symbol graph data structures
│   ├── Shape/               # Type transformation passes
│   ├── Normalize/           # Name reservation
│   ├── Plan/                # Import/export planning
│   ├── Emit/                # TypeScript file generation
│   └── Renaming/            # Name conflict resolution
├── test/
│   ├── scripts/             # Test scripts
│   ├── validate/            # Validation scripts
│   ├── baselines/           # Surface manifest baseline
│   └── fixtures/            # Test fixtures
└── docs/                    # Documentation

Build Commands

# Build
dotnet build src/DotnetBindgen/DotnetBindgen.csproj

# Build release
dotnet build src/DotnetBindgen/DotnetBindgen.csproj -c Release

# Run
dotnet run --project src/DotnetBindgen/DotnetBindgen.csproj -- <args>

Documentation

Related Projects

License

MIT

About

Generate d.ts files for a .Net assembly

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors