guide/src/reference/attributes/on-js-imports/slice_to_array.md
slice_to_arrayBy default, an &[T] argument to an imported JS function uses one of two
representations on the JS side:
T (u8, i32, f64, ...) the slice arrives as a
zero-copy typed-array view into linear memory (e.g. Uint8Array,
Float64Array).String, an imported JS type, or another JsValue-shaped element
type, the slice is materialised as a plain Array of values.The slice_to_array attribute makes every &[T] (and Option<&[T]>)
argument of an imported function arrive as a plain JS Array regardless
of the element kind. The user-facing Rust signature is unchanged —
&[T] stays &[T]. Only the wire format and the JS-visible type
change.
This is useful when binding JS APIs that expect a plain T[] (e.g.
Array<number>) rather than a typed array.
#[wasm_bindgen]
extern "C" {
// JS receives `Array<number>` rather than `Uint16Array`.
#[wasm_bindgen(slice_to_array)]
fn set_indices(values: &[u16]);
}
extern "C" blockThe attribute can also be written on the block to apply to every imported function inside:
#[wasm_bindgen(module = "/lib.js", slice_to_array)]
extern "C" {
fn take_numbers(v: &[i32]);
fn take_strings(v: &[String]);
fn take_optional(v: Option<&[u16]>);
}
Per-function and per-block slice_to_array combine additively — the
attribute is opt-in at either level. The mode only acts on &[T] /
Option<&[T]> arguments; any other argument shape (e.g. the this
argument of a method, or unrelated scalar arguments) is left
untouched, so it's safe to set the attribute on a method or on an
entire extern "C" block of mixed-shape imports.
For primitive element kinds the wire is the same zero-copy borrow of
the slice memory used by plain &[T]; the only difference is that the
JS-side shim wraps the typed-array view in Array.from(...) to
materialise a plain Array. No allocation, no copy on the Rust side.
For String, JsValue, and JS-imported types the Rust side builds a
freshly allocated [u32] buffer of externref indices — one per element
— that JS reads into a plain Array and then frees. Per-element
conversion is &T -> JsValue, which for handle-shaped types is a
refcount bump on the existing JS slot, and for String allocates a
fresh JS string.
&[ExportedT] remains unsupported. Use Vec<ExportedT> to
transfer ownership of a sequence of exported struct values to JS.Vec<T>. Owned vectors
passed by value continue to use their existing wire format.&[T] (zero-copy typed-array view)
behaviour for functions where slice_to_array was not opted into.