Adds support for #[wasm_bindgen(typescript_custom_section)]. #1048
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Implementation
This diff adds an attribute "typescript_custom_section", inspired by wasm_custom_section. It allows you to annotate a static const string as an addition to
wasm-bindgen
's generated TypeScript definition files.When wasm-bindgen-cli is invoked with the --typescript parameter, the contents of all typescript_custom_section strings encountered during compilation are appended to the output
.d.ts
file. This allows Rust to be the source of truth for type definitions in both WebAssembly and Typescript, or route around missing functionality inwasm-bindgen
. Most importantly, it enables external tooling to directly generate their own Typescript types.Motivation
wasm-bindgen
exports JavaScript classes and enums that mirror the structure of Rust structs and (C-style) enums. It also exports TypeScript definitions when the--typescript
flag is used. For types defined in Rust that you want to share a JSON-type definition for, you may only need to export a TypeScript definition that models it.For example, sum types can't be exported to TypeScript just using wasm_bindgen:
There is no concrete type in JavaScript that corresponds to a tagged union. But if we treat this as plain old JSON-encodable data (as when serializing using serde), we can actually create a Typescript type definition that lives alongside it to express all possible values:
The primary benefit is ensuring that Rust is the source of truth for shared type definitions (where the alternative is writing your own Typescript definition that must stay in sync with your Rust definition.) But we can leverage even stronger type guarantees, where Typescript gives you semantics that are similar to Rust's tagged unions:
Knowing that subcrates might want to define additional Typescript information is the motivating factor for
typescript_custom_section
. Rather than integrate advanced Typescript generation entirely intowasm-bindgen
, we can pull this logic wholly into external libraries.An example of this is wasm-typescript-definition, a
#[derive(TypescriptDefinition)]
macro I wrote to try out typescript_custom_section. This enables serde-Serialize
able values to export an equivalent TypeScript definition:In this case, the
#[derive(TypescriptDefinition)]
attribute would generate its own additional#[wasm_bindgen(typescript_custom_section)]
section, which would be rolled into your resulting definitions file. It's then able to be used to typecheck user code.Because this crate is intentionally serde-aware, it can export a Typescript definition that matches the serde encoding exactly. You could deserialize Rust values in Typescript with full typechecking, then return them to Rust with the same guarantee, just by using a type annotation. Using
typescript_custom_section
, no serde-aware logic needs to be added into wasm-bindgen to make this work.