Skip to content

How to use TypeScript declarations for Emscripten #10271

Open
@kbumsik

Description

@kbumsik

Related: #9674 #7083

I would like to discuss the current best way to use typing features of TypeScript with Emscripten. If you are looking for a WebIDL -> TypeScript .d.ts converter for C++ application specifically, you may refer to the above two issues.

I recently found @types/emscripten from NPM and I spent a few hours to figure out how to integrate it with my Emscripten project and contributed the package a little bit too. The .d.ts typing file can be found here: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten/index.d.ts

Suppose I make add.c like this:

// add.c
int add (int a, int b) {
	return a + b;
}

Two ways I have figured out:

  1. add--post-js.ts
  2. add.d.ts + add--post-js.js

In my case I found option 2 is better. Will be explained later.


1. add--post-js.ts

add—post-js.ts

/// <reference types="emscripten" />
/** Above will import declarations from @types/emscripten, including Module etc. */

// This will merge to the existing EmscriptenModule interface from @types/emscripten
// If this doesn't work, try globalThis.EmscriptenModule instead.
interface EmscriptenModule {
	// Module.cwrap() will be available by doing this.
	// Requires -s "EXTRA_EXPORTED_RUNTIME_METHODS=['cwrap']"
	cwrap: typeof cwrap;
	// Exported from add.cpp
	// Requires "EXPORTED_FUNCTIONS=['_add']"
	_add(number, number): number;
	// or using cwrap. See below
	add(number, number): number;
}

Module['onRuntimeInitialized'] = function() {
  // Just Module._add() will work, but I'm just demonstrating usage of cwrap()
  Module['add'] = cwrap('add', 'number', ['number', 'number']);
}

2. add.d.ts + add--post-js.js

add.d.ts

/// <reference types="emscripten" />
/** Above will import declarations from @types/emscripten, including Module etc. */

// This will merge to the existing EmscriptenModule interface from @types/emscripten
// If this doesn't work, try globalThis.EmscriptenModule instead.
export interface AddModule extends EmscriptenModule {
	// Module.cwrap() will be available by doing this.
	// Requires -s "EXTRA_EXPORTED_RUNTIME_METHODS=['cwrap']"
	cwrap: typeof cwrap;
	// Exported from add.cpp
	// Requires "EXPORTED_FUNCTIONS=['_add']"
	_add(number, number): number;
	// or using cwrap. See below
	add(number, number): number;
}

// Declare any name
declare const addModule: AddModule;
// Only for -s MODULARIZE=1
export = addModule;
// Only for -s MODULARIZE=1 -s EXPORT_ES6=1
export default addModule;

add—post-js.js

/// <reference types="emscripten" />
/** Above will import declarations from @types/emscripten, including Module etc. */
/** It is not .ts file but declaring reference will pass TypeScript Check. */

Module['onRuntimeInitialized'] = function() {
  // Just Module._add() will work, but I'm just demontrating usage of cwrap
  Module['add'] = cwrap('add', 'number', ['number', 'number']);
}

I know, both of them don't particularly look pretty but they are the cleanest ones so far.

I found that the second one is better for two reasons: add--post-js.ts file must be compiled to js in order to work with emcc command. And there are problems when you want to use export statement because -s MODULARIZE=1 creates another export statement automatically.

Please share any better tricks if you have one. Also you will notice that @types/emscripten is not complete when you look at the source code it would be great if anyone can make the package better.

Thanks :)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions