You can export an API schema describing the functions, classes, and events exposed to JavaScript as JSON.

Generating TypeScript declarations from that schema gives editors autocomplete and type checking for calls made from the page.

## Getting the Schema

Call `schema()` to read the schema as a JSON string, or `DumpSchema()` to write it directly to a file:

```cpp
std::string json = api.schema();
api.DumpSchema("myapp-schema.json");
```

The schema describes parameter and return types for every binding, named structs and enums, and declared events, along with any documentation and metadata added by native code.

## Naming Parameters and Adding Documentation

Pass `js::Param` and `js::Doc` after the callable to add parameter names and documentation to a binding:

```cpp
api.Bind("add", [](double a, double b) { return a + b; },
         js::Param("a"), js::Param("b"), js::Doc("Adds two numbers."));
```

Explicit calls like `Bind()`, `DefineEvent()`, and class methods accept these arguments. The property assignment form (`api["add"] = ...`) takes no annotations.

### Annotation Rules

You must provide a name for every parameter or leave them all unnamed. Naming only some of the parameters causes a compile error.

Parameter names appear in generated declarations, the schema, and runtime `TypeError` messages. Unnamed parameters fall back to `arg0` and `arg1`.

Documentation strings from `js::Doc` populate the `doc` field in the schema and show as hover descriptions in editors. For function binding basics, see [Extending JavaScript with Native API](/docs/2.0/extending-javascript-with-native-api).

## Adding Metadata

Call `SetMetadata()` to merge a JSON object into the schema entry at a specific path:

```cpp
api.SetMetadata("", R"({"meta": {"version": "2.1.0"}})");
```

Passing an empty string for the path targets the schema root, which holds top-level sections like `meta`, `events`, and `types`.

Objects merge field by field, and values from later calls replace earlier ones.

> 🚧 Rebinding Clears Metadata
>
> Rebinding an existing path removes its metadata. Always call `SetMetadata()` after the `Bind()` call it describes.

## Generating TypeScript Declarations

Scripts on the page call native functions without compile-time checks— any misspelled identifier or invalid argument triggers a `TypeError` only at runtime.

The `gen-typescript.py` tool in `tools/scripts/` converts an exported schema file into a `.d.ts` declaration file. Adding this file to a web project gives editors autocomplete, type checking, and hover documentation, even in plain JavaScript projects.

### Generation Steps

Generate the declaration file in three steps:

1. Export the schema file from a debug build:

```cpp
#ifndef NDEBUG
api.DumpSchema("myapp-schema.json");
#endif
```

2. Run the script to produce the declaration file:

```bash
python tools/scripts/gen-typescript.py myapp-schema.json -o myApp.d.ts
```

For the earlier `add()` binding, the script generates this declaration:

```ts
declare namespace myApp {
  /** Adds two numbers. */
  function add(a: number, b: number): number;
}
```

3. Add the `.d.ts` file to the web project.

### Checking Plain JavaScript

You can take advantage of the declarations in plain JavaScript without setting up a TypeScript build.

Add a `jsconfig.json` file beside the web files to enable type checking across the project:

```json
{
  "compilerOptions": { "checkJs": true },
  "include": ["**/*.js", "myApp.d.ts"]
}
```

To check a single file instead, add `/// <reference path="myApp.d.ts" />` and `// @ts-check` to the top of that file.

The editor flags invalid arguments and misspelled names while typing:

```js
myApp.add(1, "2");
// Argument of type 'string' is not assignable to parameter of type 'number'.
myApp.ad(1, 2);
// Property 'ad' does not exist on type 'typeof myApp'.
```

### Recommended Practices

- **Keep declarations in sync** — Automate schema export and declaration generation as a build step so types track native changes.
- **Name every parameter** — Use `js::Param` on bindings so editor autocomplete displays meaningful names instead of `arg0` and `arg1`.
- **Document exposed functions** — Add `js::Doc` to bindings so descriptions appear on hover while writing page scripts.
