Currently, TypeScript support in wasm-bindgen is all-or-nothing: either every single item annotated with #[wasm_bindgen] gets a TypeScript definition, or none of them do.
While the generated bindings are useful, they currently contain lots of anys, and it's unlikely wasm-bindgen will be able to produce strict typings for JsValues without lots of additional work like #1197.
This can be partially worked-around in the meantime, with typescript_custom_section:
[wasm_bindgen(typescript_custom_section)]
const TS_FOO_TYPE: &'static str = r#"
export function foo(bar: (x: number) => number): void;
"#;
#[wasm_bindgen]
pub fn foo(bar: js_sys::Function) {
// call bar, handling errors if the wrong function signature is passed
}
However, this will generate two TypeScript definitions:
The automatic export function foo(bar: any): void; and the custom export function foo(bar: (x: number) => number): void;
This does still add utility, since you can get IDE suggestions for what types you should pass, but it doesn't cause TypeScript to enforce passing the correct types, since it will still accept any as a parameter.
I propose an attribute to prevent emitting TypeScript definitions for a specific #[wasm_bindgen]'d item.
It could look something like #[wasm_bindgen(typescript = false)]
This would not autogenerate or emit any typescript bindings for that item.
This would allow developers to provide their own type definitions that replace the autogenerated ones, and allow third-parties to write a crate that provides something like #1197 without it having to be part of wasm-bindgen itself.
My only concern is that this feature encourages maintaining two copies of a function signature, where it would be easy to update either the Rust or TypeScript signature and forget to update the other. However, there's no solution to this problem without much more advanced TypeScript type generation than js_sys and wasm-bindgen currently support.
A way to emit custom typescript for specific parameters or return types for a function could function in a similar way. I believe this would take more work to implement than simply not emitting TypeScript definitions per-item and letting developers inline the strict definition in a typescript_custom_section.
We could instead implement #1197, but that's a big complicated issue - this feature would allow developers to start using more strict TypeScript types immediately.
Seems reasonable to me! I'd also be ok with a system like:
#[wasm_bindgen(typescript(bar = "(x: number) => number"))]
pub fn foo(bar: js_sys::Function) {
// call bar, handling errors if the wrong function signature is passed
}
or something like that where you can customize the listed type of arguments if necessary. Either way a PR sounds good to me!
@alexcrichton I really like the general idea. One thing that comes to mind in terms of limitation to this is the need of additional types which related to the signature.
If I ultimately want an output like this:
interface LabeledValue {
label: string;
}
function foo(bar: LabeledValue) {
// TODO
}
There is no way to do that localized using this form since there is not place for adding LabeledValue interface. One could use #[wasm_bindgen(typescript_custom_section)] but that is almost global.
#[wasm_bindgen(typescript(bar = "LabeledValue"))]
pub fn foo(bar: &JsValue) {
// call bar, handling errors if the wrong function signature is passed
}
Not proposing any solutions here. Just helping with the conversation by pointing out a possible drawback with the proposed idea above.
Would this allow web-sys to emit HTMLElement and such rather than becoming any? Or is there something else that's causing this?
@trivigy I don't imagine this issue would cover automatic generation of these typescript types, just a way to emit custom TS for wasm_bindgen'd functions. It would be up to the user (or another crate) to write a typescript_custom_section that makes sense and doesn't include any conflicting type definitions.
@bennetthardwick I believe that yes, this feature would allow web-sys to replace the default any types with custom types. However, the types emitted would need to be explicitly annotated, it wouldn't be a switch you flip and suddenly get correct TS definitions :)
I would prefer an override over the function instead / in addition. Currently the issue with removing the old typing and creating a new one is that the documentation and js type docs are now no longer generated. I would prefer a solution that allows overriding typing on individual parameters / return types independently, thus preserving the rest of the mechanism
Most helpful comment
Seems reasonable to me! I'd also be ok with a system like:
or something like that where you can customize the listed type of arguments if necessary. Either way a PR sounds good to me!