emscripten-core / emscripten-core/emscripten

How to use TypeScript declarations for Emscripten

Open
#10,271 27 comments 12 reactions 0 assignees View on GitHub
embind JavaScript
Dominant language
C++
Stars
27.6k
Forks
3.6k
Avg merge
1d 1h
Merged PRs (30d)
105

Description

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](https://www.npmjs.com/package/@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](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten/index.d.ts)

Suppose I make `add.c` like this:
```c
// 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
```typescript
///
/** 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

```typescript
///
/** 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
```javascript
///
/** 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](https://www.npmjs.com/package/@types/emscripten) is not complete when you look at [the source code](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten/index.d.ts) it would be great if anyone can make the package better.

Thanks :)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.