v149 · WebAssembly · WasmGC
JS Interop Explorer
Custom descriptors let a WasmGC struct declare its own JavaScript prototype — so wasmObj.method() just works without any hand-written wrapper. This explorer simulates both the old wrapper pattern and the new descriptor pattern side by side, letting you call methods, check instanceof, and enumerate properties on live objects.
Before custom descriptors — JS wrapper class
// Old pattern: Counter is a JS class wrapping Wasm exports
// const obj = new Counter(42);
// const obj = new Counter(42);
After custom descriptors — direct prototype
// New pattern: Counter prototype wired by the descriptor
// const obj = wasmModule.createCounter(42);
// const obj = wasmModule.createCounter(42);
instanceof and prototype chain checks
// === Before: hand-written JS wrapper (boilerplate) ===
class Counter {
// Stores a Wasm ptr; every method delegates to Wasm exports
constructor(init) { this._ptr = exports.counter_new(init); }
getValue() { return exports.counter_get(this._ptr); }
increment() { exports.counter_inc(this._ptr); }
}
// === After: custom descriptor (declared inside the .wasm) ===
// The .wasm declares:
// (type $Counter (struct (field i32)))
// (type $CounterDescriptor (descriptor $Counter))
// (func getValue ...) (func increment ...)
// Chrome 149 reads the descriptor and wires up the JS prototype.
// The JS side just does:
const obj = wasmModule.exports.createCounter(42);
obj.getValue(); // → 42 (no wrapper needed)
obj.increment(); // works — method on prototype, shared across all instances
see also
- Prototype Bridge — side-by-side wrapper vs descriptor
- Type-Safe Objects — type boundary enforcement
- Method Dispatch Bench — performance comparison
- Memory Footprint Demo — shared prototype memory savings
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗