Functions
Contents
There is one rule for what makes a JS-visible function:
Env and CallInfo are recognized by type and injected automatically. They never consume a JS argument. Everything else is converted from the JS arguments at the call site, and the return value is converted back.
The progression
Three flavors of function, in order of how often you need them.
Just values
The simplest case: take JS arguments, return a value. No environment needed.
If your function does not allocate, throw, or call back into JS, this is all you need. add(i32, i32) does not even touch the allocator.
Take an Env
Add env: napi.Env as the first parameter when you need to allocate, build complex JS values, or throw.
env.allocator() is an arena that resets when your function returns. See Memory model.
Take raw CallInfo
For variadic or dynamic-arity functions, take info: napi.CallInfo and pull out the arguments yourself.
This is the escape hatch when the static type system cannot describe what you want.
Returning your own JS values
For values the auto-converter cannot build (Buffers, dynamic-key objects, hand-built arrays), return !napi.Val and construct it yourself:
napi.Val is a passthrough type. Anywhere a JS value is expected (return values, callback arguments, struct fields), you can substitute a Val and it travels through unconverted.
Naming
Field and function names are translated from snake_case to camelCase automatically. Both forms work in the published .d.ts:
If you want a JS-visible name that is not a valid Zig identifier, build the export manually with env.createObject() and setNamedProperty.
What's next?
- Namespaces explains how
pub const x = struct { ... }becomes a nested object. - Type conversion is the table of every Zig type and what it maps to in JS.
- Errors covers throwing, rejecting, and the
napi.Errorset.