/** * emit-shared-typescript-typed.ts — TS TypedMaterializer runtime-materialization hooks + the * reachable native typed layer (bc#135). * * The TypedMaterializer seam (typed.ts) exposes runtime-materialization hooks — `emitMarshallers`, * `materializeExpr`, `typedFieldAccess`, `serializeTyped` — that the COMPILE languages (go/rust, * #47/#48) implement to de-box a raw `Value` into a concrete struct. `typescript-typed` (the #46 * oracle) implements ONLY the decls-only subset (`emitTypeDecls`/`renderTypeRef`) and leaves the * runtime hooks unimplemented — its typed layer is a dead-on-runtime verification oracle. * * This module implements the runtime-materialization hooks for TS (`tsNativeTypedMaterializer`) and * assembles the REACHABLE typed layer (`emitNativeTypedLayer`) the `typescript-native` emitter puts * on top of the straight-line runtime body: * - `emitTypeDecls` / `renderTypeRef`: interface declarations + type annotations (shared discipline * with the oracle — reused verbatim from emit-straightline-typed-typescript.ts). * - `emitMarshallers`: for every named interface T*, a `marshalT*(v: Value): T*` that materializes * a boxed `Value` into the declared interface by reading each declared field — the de-interpreted * shape walk (no generic Value tree-walk in the typed entry path). Under TS erasure the field * reads are dynamic and the leaf `as` is a no-op; that is the handler `Value` boundary (expected). * - `materializeExpr`: materialize a raw `Value` expression into a `TypeRef` (marshaller call for * obj, element-map for arr, null-branch for opt, cast for scalar). * - `typedFieldAccess`: static typed field access on an already-materialized base (`base["f"]["g"]`) * — tsc checks the path against the interface. * - `serializeTyped`: identity at the boundary (TS values are already the canonical JS shape; the * equivalence pin is that the straight-line body produced the value). * * The typed layer is REACHABLE: `bindTyped(handlers)` runs the straight-line `bind()` runner and * materializes each covered component's result through `marshalOutput_` into the component's * `outputType`. So the `as T` boundary + typed field access sit on a LIVE typed path (not a dead * oracle). Runtime is byte-identical to the straight-line body (marshalling returns the same value, * retyped); `tsc --strict` proves the typed surface. * * HONEST NOTE (bc#31/#32): TS erasure ⇒ no runtime de-box win. The marshaller is a validated * pass-through, NOT a monomorphized struct materialization like go/rust. Its value is compile-time * type safety + an honest codegen surface, not perf. */ import type { EmitContext } from "./core.js"; import { deriveTypeRef, type TypePlan, type TypeRef, type TypedMaterializer } from "./typed.js"; /** Render a TypeRef to a TS type annotation (scalar/opt/arr inline; obj → named interface ref). */ export declare function renderTypeRef(ref: TypeRef): string; /** Emit the named interface declarations (decls order = deterministic). */ export declare function emitTypeDecls(plan: TypePlan): string; /** * materializeExpr — materialize a raw `Value` expression into a value of the annotated `ref`: * - named (obj) → `marshalT*(rawExpr)` (the shape walk), * - arr → `(rawExpr as Value[]).map((e) => )`, * - opt → `(rawExpr === null ? null : )`, * - scalar → typed cast `(rawExpr as )`. * Under TS erasure the scalar cast is a no-op — that IS the handler Value boundary (expected). */ export declare function materializeExpr(rawExpr: string, ref: TypeRef, _plan: TypePlan): string; /** * emitMarshallers — for every named interface T*, a `marshalT*(v: Value): T*` that materializes a * boxed `Value` into the declared interface by reading each declared field (the de-interpreted shape * walk). Deterministic (decls order). Empty when there are no named decls. */ export declare function emitMarshallers(plan: TypePlan): string; /** * typedFieldAccess — static typed field access on an already-materialized base (`base["f"]["g"]`). * Returns the access expression and the type reached (per the plan decls). tsc checks the path * against the interface (a field not on the interface is a compile error — the non-vacuous pin). */ export declare function typedFieldAccess(baseExpr: string, baseRef: TypeRef, fields: string[], plan: TypePlan): { expr: string; ref: TypeRef; }; /** * serializeTyped — identity at the boundary. In TS the typed value IS already the canonical JS shape * (erasure), so no re-serialization is needed for the equivalence pin: the straight-line body produced * the canonical Value and the marshaller returned the same value retyped. */ export declare function serializeTyped(typedExpr: string, _ref: TypeRef, _plan: TypePlan): string; /** The TS runtime-materialization TypedMaterializer (bc#135) — the seam go/rust also ride. */ export declare const tsNativeTypedMaterializer: TypedMaterializer; /** * emitNativeTypedLayer — the REACHABLE typed layer appended to the straight-line runtime body: * interfaces + marshallers + per-component output marshallers + a `bindTyped`/`bindTypedAsync` facade * that runs the straight-line `bind()` runner and materializes each covered component's result into * its `outputType`. This is what makes the typed layer live (not a dead oracle): the `as` boundary and * typed field access are on a real typed entry path that `tsc --strict` verifies. */ export declare function emitNativeTypedLayer(ctx: EmitContext, plan: TypePlan, mat: TypedMaterializer, derive: typeof deriveTypeRef): string; //# sourceMappingURL=emit-shared-typescript-typed.d.ts.map