Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an attribute to prevent emitting typescript definitions for a specific #[wasm_bindgen]'d item #1691

Closed
arilotter opened this issue Aug 1, 2019 · 5 comments · Fixed by #2016

Comments

@arilotter
Copy link
Contributor

Motivation

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.

Proposed Solution

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.

Alternatives

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.

@arilotter arilotter added the enhancement New feature or request label Aug 1, 2019
@alexcrichton
Copy link
Contributor

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!

@trivigy
Copy link

trivigy commented Dec 11, 2019

@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.

@bennetthardwick
Copy link
Contributor

Would this allow web-sys to emit HTMLElement and such rather than becoming any? Or is there something else that's causing this?

@arilotter
Copy link
Contributor Author

@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 :)

@screepsunleashed
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants