How to import WebAssembly functions to TypeScript?

Viewed 5127

I have an existing project written in TypeScript and I'm trying to import a WebAssembly Module to replace some functionality.

I have managed to successfully import the WebAssembly module by extracting the logic for loading the .wasm to a .js file. This is it's own TypeScript module and is imported into the .ts file where I want to use the WebAssembly functions.

For demonstration purposes I have made a simple add function in wasm.

In the .ts that is compiled to .wasm with AssemblyScript:

export function add(a: i32, b: i32): i32 {
  return a + b;
}

In the .js file:

export async function loadWasm() {
  const imports = {}; // Omitted the contents since it's most likely irrelevant
  const module = await 
  WebAssembly.instantiateStreaming(fetch('path/to/file.wasm'),imports);
  return module;
}

And in the .ts file where I want to use the WebAssembly:

loadWasm().then((module: any) => {
  let addFunc: ((a: number, b: number) => any) = module.add;
  console.log('Adding 2 and 5 in Wasm: ' + addFunc(2, 5));
});

But when running this it gives me the following error:

Uncaught (in promise) TypeError: addFunc is not a function at eval

Does anyone know what causes this?

2 Answers

Try this snippet:

loadWasm().then(module => {
  const { add: addFunc } = module.instance.exports;
  console.log(addFunc(2, 5));
});

Here's a method using AssemblyScript Loader that you can use directly in the TypeScript:

It requires "regenerator-runtime": "^0.13.2" which you can import together with the loader in the .ts file where you want to use the Wasm module, as such:

import { instantiateStreaming, ASUtil } from 'assemblyscript/lib/loader';
import { regeneratorRuntime } from 'regenerator-runtime';

I've instantiated it like so:

interface MyApi {
    add(a: number, b: number): number;
}

async function getWasm(): Promise<ASUtil & MyApi> {
    const imports: any = {};
    let module: ASUtil & MyApi = await instantiateStreaming<MyApi>(fetch('path/to/file.wasm'), imports);
    return module;
}

After which you can simply:

getWasm().then((module) => {
    console.log('The result is: ', module.add(3, 4));
});

As well as use any of the additional functionality that the Loader provides:

let str = "Hello World!";
let ref = module.__retain(module.__allocString(str));
console.log(module.__getString(ref));
Related