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

How to get more detailed type information in .d.ts #1197

Open
dlesl opened this issue Jan 20, 2019 · 11 comments
Open

How to get more detailed type information in .d.ts #1197

dlesl opened this issue Jan 20, 2019 · 11 comments

Comments

@dlesl
Copy link

dlesl commented Jan 20, 2019

Hi!
At the moment it's possible to pass pretty much anything between Rust and js as a JsValue, or using js-sys, however it would be nice to have a way to provide more detailed information in the .d.ts files.
For example, I can return an array of rust structs as Box<[JsValue]>, which in typescript becomes any[]. If I return js_sys::Promise, I get Promise<any>.

Would it be a good idea to add type parameters to the types in js-sys, so that you could return Array<SomeStruct> in rust? Of course, js arrays can contain mixed types, but that could still be represented by Array<JsValue>.

Would this be making things unnecessarily complex?

@alexcrichton
Copy link
Contributor

This is a good question! Currently we generally do typing in .d.ts on a best-effort basis, but the support has been somewhat languishing for some time. It'd be great if we could expose a much more rich set of types, but getting it all hooked up in a robust fashion is often pretty difficult. I think the best thing to do would be to basically experiment here to see what we can expose, and in the meantime adding manually written wrappers to add types for TypeScript

@alexcrichton
Copy link
Contributor

Note that there are some low-hanging fruit ones though, like we could handle any[] pretty easily I think

@ThomasdenH
Copy link
Contributor

Ideally an extern "C" type would generate a corresponding Typescript interface/type when it's used at code boundaries.

@Michael-F-Bryan
Copy link

Ideally an extern "C" type would generate a corresponding Typescript interface/type when it's used at code boundaries.

I was thinking the same. For example, my code accepts a JavaScriptCallbacks object with several methods, like so:

#[wasm_bindgen]
extern "C" {
    pub type JavaScriptCallbacks;

    #[wasm_bindgen(method)]
    fn unknown_content(this: &JavaScriptCallbacks, text: &str, span: Span);

    #[wasm_bindgen(method)]
    fn gcode_buffer_overflowed(
        this: &JavaScriptCallbacks,
        mnemonic: char,
        major_number: u32,
        minor_number: u32,
        span: Span,
    );

    ...
}

#[wasm_bindgen]
impl Parser {
    #[wasm_bindgen(constructor)]
    pub fn new(text: String, callbacks: JavaScriptCallbacks) -> Parser {
        ...
    }
}

This currently (as of v0.2.59) generates the following index.d.ts:

export class Parser {
  free(): void;
  constructor(text: string, callbacks: any);
}

However to prevent errors due to missing methods or bad signatures at runtime it'd be awesome if the type declarations also contained a JavaScriptCallbacks interface. index.d.ts might then look something like this:

export interface JavaScriptCallbacks {
  unknown_content(text: string, span: Span): void;

  gcode_buffer_overflowed(
    mnemonic: string,
    major_number: number,
    minor_number: number,
    span: Span,
  ): void;
}

export class Parser {
  free(): void;

  constructor(text: string, callbacks: JavaScriptCallbacks);
}

@Pauan
Copy link
Contributor

Pauan commented Mar 8, 2020

@Michael-F-Bryan You can already do that:

#[wasm_bindgen(typescript_custom_section)]
const TS_JAVASCRIPT_CALLBACKS: &'static str = r#"
export interface JavaScriptCallbacks {
  unknown_content(text: string, span: Span): void;

  gcode_buffer_overflowed(
    mnemonic: string,
    major_number: number,
    minor_number: number,
    span: Span,
  ): void;
}
"#;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(typescript_type = "JavaScriptCallbacks")]
    pub type JavaScriptCallbacks;

    #[wasm_bindgen(method)]
    fn unknown_content(this: &JavaScriptCallbacks, text: &str, span: Span);

    #[wasm_bindgen(method)]
    fn gcode_buffer_overflowed(
        this: &JavaScriptCallbacks,
        mnemonic: char,
        major_number: u32,
        minor_number: u32,
        span: Span,
    );

    ...
}

Though it would be nice if it could be automated by wasm-bindgen.

@septatrix
Copy link

The ideal solution would probably be close to what was proposed in a comment in another issue: #1591 (comment)

@stan-irl
Copy link

+1 would really like to see this.

IMO this is a must have if you have many people working on the codebase. You need build time checks for API compatibility. It's so easy to accidentally miss something and blow up your site.

@ivnsch
Copy link
Contributor

ivnsch commented Nov 24, 2022

I started a project for this: https://github.com/ivanschuetz/export_ts_macro

It's a basic proof of concept (only exports string and u64 fields for now) and I'm not well versed with macros (started learning just yesterday), but it seems to work.

@ivnsch
Copy link
Contributor

ivnsch commented Nov 24, 2022

Someone recommended tsify to me, which seems to do this.

@stan-irl
Copy link

Very cool! onepassword has just released typeshare a few days ago as well which is also similar: https://github.com/1Password/typeshare.

Unfortunately it doesnt really look like any of these support passing a typed interface from TS to rust. The specific usecase I'm after here is one @ThomasdenH mentions above - When I pass a delegate from TS/JS into rust. I want to statically check that the interface is satisfied when I'm building my TS.

@ivnsch
Copy link
Contributor

ivnsch commented Nov 25, 2022

Ah! I found this while looking how to export simple definitions and didn't read the whole conversation. Just for the record, tsify is specific for wasm-bindgen. I wasn't able to figure out how to connect the bindgen types with the more generic exporters (I tried with rust-typescript-type-def) before I found tsify.

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

No branches or pull requests

8 participants