Tsonic GitHub
Edit on GitHub

Language Model

Tsonic is not “all TypeScript plus best effort.” It is a strict subset designed for deterministic lowering to C#.

The model

  • one compiler-owned noLib baseline
  • one ambient surface per workspace
  • explicit package imports for CLR and Node/Express usage
  • no hidden permissive runtime bridges

Consequences of that model

This affects how you should read and write Tsonic code:

  • ambient behavior comes from the selected surface, not from whichever package happens to be installed
  • authored source packages are compiled as part of the same program
  • unsupported dynamic behavior is rejected instead of being preserved
  • generated output is treated as a closed world
  • runtime reflection and runtime shape discovery are not language semantics

What that means in practice

  • unsupported dynamic constructs are rejected
  • explicit numeric intent matters
  • package graphs are compiled deterministically
  • emitted output is treated as a closed world
  • JSON APIs require concrete compile-time types so generated serializers can be rooted for NativeAOT

Flow facts versus runtime dynamic probing

Tsonic accepts TypeScript flow facts only when the compiler can also prove a deterministic NativeAOT-safe carrier operation.

Accepted examples:

export function read(value: string | undefined): string {
  if (typeof value === "string") {
    return value;
  }

  return "";
}

export function hasKey(value: Record<string, number>): boolean {
  return "total" in value;
}

The first example narrows a closed primitive union. The second example uses a string-literal key against a statically proven dictionary carrier, so the generated code lowers to the typed dictionary key operation.

Rejected examples:

const kind = typeof value;
"name" in (value as object);
"name" in ({ name: "x" } as { name?: string });
delete value.name;
for (const key in value) {
}
await import("./module.js");
import.meta.url;
globalThis;

Use concrete domain types, static imports, explicit discriminant fields, compiler-recognized guards, for...of over typed collections, and typed JSON APIs.

Use the right docs