Tsonic GitHub
Edit on GitHub

Type Mappings

Core numeric mapping

  • number -> double
  • int -> System.Int32
  • long -> System.Int64
  • float -> System.Single
  • decimal -> System.Decimal
  • bool -> bool
  • char -> char

Explicit branded numeric types from @tsonic/core/types.js exist so callers can force CLR intent where number would be too vague.

Nullability and option-like shapes

  • undefined / null are preserved according to the active surface and target shape
  • unknown is the broad boundary type for values whose useful runtime shape is not proven at the declaration boundary
  • optional properties are not treated as permission for arbitrary dynamic object use
  • nullish coalescing still has to lower to a stable target type

Strings, arrays, tuples, and objects

  • string -> CLR string with surface-dependent API exposure
  • arrays -> native arrays or deterministic helper-backed shapes depending on context
  • tuples -> ValueTuple-style lowered shapes
  • object literals -> emitted only when the runtime shape can be represented deterministically

The important point is that lowering is contextual. Tsonic does not promise one single universal CLR representation for every TS construct regardless of usage.

Collections

  • TypeScript arrays -> native C# arrays or surface/runtime helpers depending on context
  • tuples -> ValueTuple
  • dictionaries and sets -> explicit CLR or JS-backed shapes depending on the authoring surface and contextual target

Imported CLR types stay explicit

Explicit CLR imports do not become “more JavaScript” just because the workspace surface is @tsonic/js.

Example:

import { Dictionary } from "@tsonic/dotnet/System.Collections.Generic.js";

const map = new Dictionary<string, number>();

That is still a CLR binding package call surface.

Generated CLR binding packages project System.Object as TypeScript unknown and value-type constraints as NonNullable<unknown>. Those mappings keep broad CLR slots explicit while preventing source-level code from treating a broad value as an arbitrary dynamic object.

Surface effect

Surface selection selects the ambient API, not the meaning of explicit CLR imports.

Example:

const xs = [1, 2, 3];
xs.map((x) => x + 1);

still lowers through deterministic runtime machinery, not by pretending CLR APIs were authored directly.