An invoice calculator split the way a real project often is: the arithmetic in Refingere, where every amount is an exact number of cents, and the presentation in JavaScript, which already knows how every locale writes money - and a TypeScript front end calls the arithmetic like any other module.
Amounts are U64 cents, and integers keep their type, so nothing is ever rounded by accident - only the tax, half up, once. A total too large for a U64 is an OverflowError, passed up with !!, never a wrong number - the third test checks it.
@js joins a function to JavaScript, and which way depends on whether it has a body. formatMoney, systemLocale and share have none: they're declarations of JavaScript functions, money.ts's exports - @js("./money.ts", "formatShare") gives the export a name of its own. The U64 cents arrive in JavaScript as a number - or a bigint past 253 - and the string that comes back is a String. totals and receipt have bodies: they're Refingere functions, and @js makes them callable from JavaScript. See JavaScript and TypeScript.
--run and --test see that the program calls JavaScript and run it on Bun. Compiled without --js, invoice.wasm is a plain WASI program for wasmtime - there, totals and receipt are ordinary functions, and only a call reaching one of the JavaScript declarations stops, saying so.
--compile --js writes a loader for totals and receipt, invoice.mjs, with money.ts bundled in, and invoice.d.mts with their types - an Invoice is an object type with a lines array, just as the struct has it. The object passed in becomes an Invoice, each quantity a U32, and a total that overflows would be thrown as an Error.
@js declarations calling a TypeScript module.@js definitions called from TypeScript, through a generated loader and types.U64, and overflow as an error.