Rust type mapping

The target maps exact source evidence and sealed ownership facts, not TypeScript display names.

See native numbers for exact integer ranges, numeric operations, literal handling and explicit truncation.

Source contractRust representation
boolean / boolbool
int8…uint128matching Rust fixed-width integer
nativeInt, nativeUintisize, usize
ordinary bigintarbitrary-precision runtime BigInt
float32, float64f32, f64
stringString or &str only when complete use analysis proves the ABI
`Tnull, T
mutable dense T[]Vec<T> or selected JS array carrier
readonly array parameterborrowed slice when the closed ABI proves it
homogeneous fixed tuple / FixedArray<T, N>[T; N] when exact length and element carrier are proven
heterogeneous tupleRust tuple
Ref<T, L>, Mut<T, L>&'l T, &'l mut T
Pointer<T>tsonic_rust_runtime::Location<T>
NativePointer<T>, constPtr<T>, mutPtr<T>native raw pointer with exact mutability
closed structural objectgenerated Rust record/enum/trait representation selected by layout policy
producer-owned broad valuefinite tsonic_rust_js::JsValue carrier for proved operations

Provider-backed values retain exact crate, module, item, generic, lifetime, const, associated-type, ABI, safety, fallibility, and foundation identities. No source type is silently boxed merely to make an unsupported operation compile.

Fixed arrays

The fixed-array carrier retains the exact extent as an integer constant in [T; N], including bigint source extents, without converting it through a JavaScript number. Native usize representability and allocation limits remain native constraints; exact emitted constants do not certify those constraints.

Source .length uses the native array’s usize result, including arrays with bigint source extents. It is not narrowed to int32 or converted through a floating-point value. An explicit as int32 conversion checks the native range; a declaration annotation does not silently narrow a native-word length. Literal index/cardinality checks and rest bounds use exact counts, and iteration retains native bounds. A representable extent alone does not guarantee that an array can be allocated or that every fixed-array operation is supported.

The shared layout contract supports array metadata observations without materializing [T; N], including huge zero-sized arrays. Raw conversion and demanded backing support fixed arrays of native Copy scalars and value records, including nested arrays, using the declared element layout and stride. Reads produce independent [T; N] values; writes preserve aliases to the raw region. Zero-sized elements require no per-element memory operation, even for large exact extents. Reference-valued elements and counts outside the selected address width remain rejections.

Broad values

An any or unknown annotation does not select a general Rust carrier:

export function keep(value: unknown): unknown {
  return value;
}

This is rejected when the parameter must cross the Rust ABI without a concrete carrier. Narrowing it first is ordinary TypeScript and produces a concrete target type:

export function text(value: unknown): string {
  return typeof value === "string" ? value : "not text";
}

An approved producer can select a finite broad carrier. Under the JavaScript surface, for example, JSON.parse produces JsValue; a matching JSON or JS operation may consume that value. This is exact producer evidence, not a spelling-based conversion from arbitrary any.

See TypeScript types and utilities for the pinned utility inventory and the target-neutral any and unknown rules.

Absence

null and undefined are the same native absence, including on the JavaScript and Node surfaces. A value that is absent compares equal to either spelling. Zero, false and an empty string remain present values. Optional chaining and ?? test absence without replacing these values.

There is no separate undefined runtime object or tag. For closed dynamic values, string conversion renders absence as "null", numeric conversion produces zero, and typeof reports "object". JSON writes a present absent-valued member as null; it does not omit that member to imitate JavaScript undefined. A missing dictionary key remains different from a present key holding JSON null. Use a collection membership query when that distinction matters.