Type Declarations
Bootsharp will automatically generate type declarations for interop APIs when building the solution. One .g.d.mts file is emitted per C# namespace, colocated with the matching .g.mjs binding under the generated/modules directory of the compiled module package.
Function Declarations
For interop methods, function declarations are emitted under the class's TS namespace wrapper inside the C# namespace's module:
public class Class
{
[Export]
public static void Baz() { }
}— will make the following emitted in generated/modules/index.g.d.mts:
export namespace Class {
export function baz(): void;
}— which allows consuming the API in JavaScript as:
import { Class } from "bootsharp";
Class.baz();Imported methods will be emitted as properties, which have to be assigned before booting the runtime:
public partial class Class
{
[Import]
public static partial void Baz();
}export namespace Class {
export let baz: () => void;
}import { Class } from "bootsharp";
Class.baz = () => {};Overloaded Methods
JavaScript does not have function overloads, so Bootsharp automatically disambiguates them when projecting overloaded C# methods. The overload with the fewest parameters keeps the original name; the rest are suffixed with With... derived from the extra parameter names (or, when that is still ambiguous, from the full parameter names or parameter types).
public class Class
{
[Export] public static void Start (string title) {}
[Export] public static void Start (string title, string info) {}
[Export] public static void Start (string title, double progress) {}
[Export] public static void Start (string title, string info, double progress) {}
}export namespace Class {
export function start(title: string): void;
export function startWithInfo(title: string, info: string): void;
export function startWithProgress(title: string, progress: number): void;
export function startWithInfoAndProgress(title: string, info: string, progress: number): void;
}Default Arguments
C# method parameters with default values are emitted as optional TypeScript parameters using the ?: syntax, letting callers omit them at the call site:
public class Class
{
[Export]
public static void Greet (string name, string greeting = "Hello") {}
}export namespace Class {
export function greet(name: string, greeting?: string): void;
}import { Class } from "bootsharp";
Class.greet("World");
Class.greet("World", "Hi");Property Declarations
Exported properties are emitted as variables under the declaring class's TS namespace:
public class Class
{
[Export]
public static string Baz { get; set; } = "";
}export namespace Class {
export let baz: string;
}import { Class } from "bootsharp";
Class.baz = "updated";Imported properties are emitted as accessor pairs, which have to be assigned before booting the runtime:
public static partial class Class
{
[Import]
public static partial string Baz { get; set; }
}export namespace Class {
export let baz: { get: () => string; set: (value: string) => void };
}import { Class } from "bootsharp";
let baz = "";
Class.baz = { get: () => baz, set: value => baz = value };Event Declarations
Exported events are emitted as EventSubscriber objects:
public class Class
{
[Export]
public static event Action<string>? OnBaz;
}export namespace Class {
export const onBaz: EventSubscriber<[payload: string]>;
}import { Class } from "bootsharp";
Class.onBaz.subscribe(payload => {});Imported events are emitted as EventBroadcaster objects:
public static partial class Class
{
[Import]
public static event Action<string>? OnBaz;
}export namespace Class {
export const onBaz: EventBroadcaster<[payload: string]>;
}import { Class } from "bootsharp";
Class.onBaz.broadcast("updated");Delegate Declarations
Custom delegates are emitted as TypeScript function-type aliases:
public delegate void Notify (string msg);
public class Class
{
[Export]
public static Notify GetNotify () => msg => Console.WriteLine(msg);
}export type Notify = (msg: string) => void;
export namespace Class {
export function getNotify(): Notify;
}import { Class } from "bootsharp";
const notify = Class.getNotify();
notify("hello");Built-in System.Action and System.Func variants are supported as well:
public class Class
{
[Export] public static Action<string>? Logger { get; set; }
}export namespace Class {
export let logger: system.Action<string> | undefined;
}import { Class } from "bootsharp";
Class.logger = msg => console.log(msg);
Class.logger("hello");Documentation Declarations
When an inspected assembly has XML documentation generated, Bootsharp mirrors the matching documentation into the emitted TypeScript declarations.
/// <summary>Math API.</summary>
public class MathApi
{
/// <summary>Adds two numbers.</summary>
/// <param name="left">Left number.</param>
/// <param name="right">Right number.</param>
/// <returns>The sum.</returns>
[Export]
public static int Add (int left, int right) => left + right;
}/**
* Math API.
*/
export namespace MathApi {
/**
* Adds two numbers.
* @param left Left number.
* @param right Right number.
* @returns The sum.
*/
export function add(left: number, right: number): number;
}Nullability
Bootsharp uses different TypeScript nullish forms depending on where a nullable C# value appears:
- nullable method arguments become
| undefined - nullable properties become optional with
? - nullable return values become
| null - nullable collection elements and dictionary values become
| null
This is intentional and optimized for TypeScript ergonomics: undefined fits omitted or optional inputs, while null fits explicit data crossing the interop boundary.
Namespaces
Members declared inside a C# namespace are emitted into a module path derived from that namespace: dots become path separators and casing is lower-kebab-cased. Members without a namespace land in the default index module (as shown in the examples above).
namespace Foo.Bar;
public class Class
{
[Export]
public static void Baz () { }
}import { Class } from "bootsharp/foo/bar";
Class.baz();You can control how the C#-side namespace path resolves to the generated module path with the Space and Name options in preferences.
Configuring Type Mappings
You can override which type declaration is generated for associated C# types via Type patterns of emit preferences.