Language Intrinsics
Tsonic includes a small set of language intrinsics in @tsonic/core/lang.js. These are TypeScript declarations that compile to C# keywords and special forms.
import {
stackalloc,
sizeof,
nameof,
defaultof,
trycast,
asinterface,
istype,
} from "@tsonic/core/lang.js";
stackalloc
Allocate stack memory and get a Span<T>:
import { Console } from "@tsonic/dotnet/System.js";
import { stackalloc } from "@tsonic/core/lang.js";
import { int } from "@tsonic/core/types.js";
export function main(): void {
const buffer = stackalloc<int>(256);
buffer[0] = 42;
Console.WriteLine(`First: ${buffer[0]}`);
Console.WriteLine(`Length: ${buffer.Length}`);
}
This emits C# like:
Span<int> buffer = stackalloc int[256];
buffer[0] = 42;
sizeof
Get the size (bytes) of an unmanaged type:
import { sizeof } from "@tsonic/core/lang.js";
import { int } from "@tsonic/core/types.js";
const bytes: int = sizeof<int>();
defaultof
Get the default value for a type:
import { defaultof } from "@tsonic/core/lang.js";
import { int } from "@tsonic/core/types.js";
const zero: int = defaultof<int>();
const nothing = defaultof<object>(); // null
nameof
Get a symbol name as a string:
import { nameof } from "@tsonic/core/lang.js";
export function main(): void {
const myVariable = 123;
const field = nameof(myVariable); // "myVariable"
void field;
}
trycast
Safe cast that returns null on failure (C# as):
import { Console } from "@tsonic/dotnet/System.js";
import { trycast } from "@tsonic/core/lang.js";
class Animal {
name!: string;
}
class Dog extends Animal {
breed!: string;
}
export function main(animal: Animal): void {
const dog = trycast<Dog>(animal);
if (dog !== null) {
Console.WriteLine(dog.breed);
}
}
asinterface
asinterface<T>(x) is a compile-time-only interface view.
It exists to treat a value as a CLR interface/nominal type in TypeScript without emitting runtime casts in C#.
import { asinterface } from "@tsonic/core/lang.js";
import { List } from "@tsonic/dotnet/System.Collections.Generic.js";
import type { IEnumerable } from "@tsonic/dotnet/System.Collections.Generic.js";
import type { ExtensionMethods as Linq } from "@tsonic/dotnet/System.Linq.js";
type Seq<T> = Linq<IEnumerable<T>>;
const xs = new List<number>([1, 2, 3]);
const seq = asinterface<Seq<number>>(xs);
// Note: asinterface is particularly important for EF Core query precompilation,
// where runtime casts can break query analyzers.
seq.Count();
istype (overload specialization)
istype<T>(x) is a compile-time-only marker used to specialize a single overload implementation
into one CLR method per signature.
Tsonic must erase istype<T>(...) before emitting C#. If it reaches emission, compilation fails with TSN7441.
import { istype } from "@tsonic/core/lang.js";
Foo(x: string): string;
Foo(x: boolean): string;
Foo(p0: unknown): unknown {
if (istype<string>(p0)) return `s:${p0}`;
if (istype<boolean>(p0)) return p0 ? "t" : "f";
throw new Error("unreachable");
}
thisarg (extension method receiver)
thisarg<T> marks the receiver parameter of a C# extension method. It is only valid on the first parameter of a top-level function declaration.
import type { thisarg } from "@tsonic/core/lang.js";
import { int } from "@tsonic/core/types.js";
export function inc(x: thisarg<int>): int {
return x + 1;
}
This emits C# like:
public static int Inc(this int x) => x + 1;
ptr (unsafe pointers)
ptr<T> is a type marker for unsafe pointer types (T*). It is defined in @tsonic/core/types.js.
import type { ptr } from "@tsonic/core/types.js";
import { int } from "@tsonic/core/types.js";
export function accept(p: ptr<int>): void {}
export function accept2(p: ptr<ptr<int>>): void {} // int**
Pointers are intended for interop and low-level scenarios; prefer safe APIs (Span<T>, IntPtr, etc.) when possible.