mastro
mastro

Reputation: 619

Rust Wasm constructor - Uncaught TypeError: Cannot read properties of undefined

I'm following the simple example as in here to export a rust struct to a React TypeScript application :

#[wasm_bindgen]
pub struct Foo {
    contents: u32,
}

#[wasm_bindgen]
impl Foo {
    #[wasm_bindgen(constructor)]
    pub fn new() -> Foo {
        Foo { contents: 0 }
    }

    pub fn get_contents(&self) -> u32 {
        self.contents
    }
}

Then I add to App.tsx the following

function App() {
let f = new Foo();
[...]

However when I run the react app I get : Uncaught TypeError: Cannot read properties of undefined (reading 'foo_new')

The struct is exported in module.js as:

export class Foo {

    static __wrap(ptr) {
        const obj = Object.create(Foo.prototype);
        obj.ptr = ptr;

        return obj;
    }

    __destroy_into_raw() {
        const ptr = this.ptr;
        this.ptr = 0;

        return ptr;
    }

    free() {
        const ptr = this.__destroy_into_raw();
        wasm.__wbg_foo_free(ptr);
    }
    /**
    */
    constructor() {
        const ret = wasm.foo_new(); <--- fails here
        return Foo.__wrap(ret);
    }
    /**
    * @returns {number}
    */
    get_contents() {
        const ret = wasm.__wbg_get_player_id(this.ptr);
        return ret >>> 0;
    }
}

and in module.d.ts as:

export class Foo {
  free(): void;
/**
*/
  constructor();
/**
* @returns {number}
*/
  get_contents(): number;
}

what am I missing?

Upvotes: 4

Views: 5337

Answers (1)

Paco Wong
Paco Wong

Reputation: 720

I encounter the same error as you do. Uncaught TypeError: Cannot read properties of undefined (reading 'foo_new') error indicates that your WASM library is not loaded. After reading the .js file generated by the WASM bindgen, I noticed that the wasm object needs to be initialized which can be done via the init function. Moreover, the init function has been exported.

export { initSync }
export default init;

Therefore, the solution to your problem is to initialize the wasm object through init function before using Foo.

Let's say the name of the Rust project is rust_wasm, I do the following:

  1. Import the functions
import rust_wasm_init from "rust_wasm";
import {Foo} from "rust_wasm";
  1. Run the functions
async run_wasm_funcion() {
    const path_to_wasm = "https://localhost:3000/static/js/rust_wasm.wasm"; //Remember to update the parameter in CopyPlugin
    await rust_wasm_init(path_to_wasm); //This initializes the wasm object mentioned above
    const foo = new Foo();
    console.log(foo.get_contents());
}

Upvotes: 4

Related Questions