Skip to content

Function

Defining a JavaScript function is very simple in NAPI-RS. Just a plain Rust fn:

lib.rs
rust
#[napi]
pub fn sum(a: u32, b: u32) -> u32 {
  a + b
}

The most important thing you should keep in mind is NAPI-RS fn does not support every Rust type. Each argument type must implement FromNapiValue, and each return type must implement ToNapiValue.

The canonical conversion matrix — argument and return types, direction, ownership, and required Cargo features — lives in Type conversions. The short version for functions:

  • Numbers (u32, i32, i64, f64), bool, and String map to their JavaScript equivalents in both directions.
  • Option<T> as an argument accepts T, null, or undefined (T | null | undefined); as a return type, None becomes null (T | null).
  • Vec<T>, tuples, HashMap, and #[napi(object)] structs map to JavaScript arrays and plain objects.
  • Buffer and the typed-array wrappers map to Buffer and TypedArray.
  • Function<Args, Return> and ThreadsafeFunction accept JavaScript callbacks with fully typed signatures (see below).
  • An async fn or an AsyncTask return maps to Promise<T>.

Return Type

The return type of a #[napi] fn is converted with ToNapiValue and appears directly in the generated .d.ts. A Result<T> return throws on Err instead of producing a value. See the Type conversions reference for the complete mapping, including BigInt output types (i64n, i128, u128) and async returns.

Function as parameter

You can pass a Function as a parameter to a fn:

lib.rs
rust
use napi::bindgen_prelude::*;
use napi_derive::napi;

#[napi]
pub fn call_function(callback: Function<u32, u32>) -> Result<u32> {
  callback.call(1)
}

⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️

index.d.ts
ts
export declare function callFunction(callback: (arg: number) => number): number

INFO

You can also create a Function at the Rust side, see Env::create_function

FnArgs

When the number of parameters exceeds 1, you can use FnArgs to define the parameters.

INFO

The tuple type can be converted to FnArgs by calling .into().

lib.rs
rust
use napi::bindgen_prelude::*;
use napi_derive::napi;

#[napi]
pub fn call_function_with_args(callback: Function<FnArgs<(u32, u32)>, u32>) -> Result<u32> {
  callback.call((1, 2).into()) 
}

⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️

index.d.ts
ts
export declare function callFunctionWithArgs(
  callback: (arg1: number, arg2: number) => number,
): number

apply

Like JavaScript, you can also use apply to call a Function with the this value.

lib.rs
rust
use napi::bindgen_prelude::*;
use napi_derive::napi;

#[napi]
pub struct RustClass {
  pub name: String,
}

#[napi]
impl RustClass {
  #[napi(constructor)]
  pub fn new(name: String) -> Self {
    Self { name }
  }
}

#[napi]
pub fn call_function_with_apply(
  this: ClassInstance<RustClass>,
  callback: Function<(), ()>,
) -> Result<()> {
  callback.apply(this, ())
}
index.ts
ts
import { callFunctionWithApply, RustClass } from './index.js'

const rustClass = new RustClass('foo')

callFunctionWithApply(rustClass, function () {
  console.log(this.name) // foo
})

create_ref

See Function Reference for more details.

build_threadsafe_function

You can build a ThreadsafeFunction from a Function by calling build_threadsafe_function.

The return type of the build_threadsafe_function is a ThreadsafeFunctionBuilder.

By default, the ThreadsafeFunctionBuilder will create a ThreadsafeFunction with the default options:

INFO

See ThreadsafeFunction for the details of options

TIP

Since you can pass ThreadsafeFunction and Arc<ThreadsafeFunction> directly to the #[napi] fn, only use the build_threadsafe_function when you are need to create a ThreadsafeFunction dynamically.

  • max_queue_size is 0
  • weak is false
  • callee_handled is true
  • error_status is napi::Status
lib.rs
rust
use napi::{bindgen_prelude::*, threadsafe_function::ThreadsafeFunctionCallMode};
use napi_derive::napi;

#[napi]
pub fn build_threadsafe_function_from_function(
  callback: Function<FnArgs<(u32, u32)>, u32>,
) -> Result<()> {
  let tsfn = callback.build_threadsafe_function().build()?;
  let jh = std::thread::spawn(move || {
    tsfn.call((1, 2).into(), ThreadsafeFunctionCallMode::NonBlocking);
  });

  Ok(())
}
Last updated on
LongYinan