rustwasm / wasm-bindgen

Facilitating high-level interactions between Wasm modules and JavaScript

Home Page:https://rustwasm.github.io/docs/wasm-bindgen/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

enum in return position have wrong type

sigmaSd opened this issue · comments

Describe the Bug

rust enums in return position are typed as object, but at runtime they're just a number

Steps to Reproduce

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub enum A {
    B,
    C,
}

#[wasm_bindgen]
pub fn b() -> A {
    return A::B;
}
import { b } from "./dist/b.js";

console.log(typeof b()); //number
console.log(b() === 0); 
error: TS2367 [ERROR]: This comparison appears to be unintentional because the types 'Readonly<{ B: 0; "0": "B"; C: 1; "1": "C"; }>' and 'number' have no overlap.
console.log(b() === 0);
            ~~~~~~~~~

wasm-bindgen 0.2.91

Weird. I think this is the bit of the generated code causing the issue:

/**
* @returns {A}
*/
export function b() {
    const ret = wasm.b();
    return ret;
}

/**
*/
export const A = Object.freeze({ B:0,"0":"B",C:1,"1":"C", });

It seems like TypeScript is interpreting the @returns {A} as @returns {typeof A} for some reason.

Is this happening in Deno? I can reproduce it with Deno, but not with plain TSC, I think because TSC automatically checks for b.d.ts and Deno doesn't. If it is, you can get Deno to use the proper type annotations instead of the JSDoc ones with @deno-types:

// @deno-types="./dist/b.d.ts"
import { b } from "./dist/b.js";

console.log(typeof b()); //number
console.log(b() === 0); 

There are 2 approaches to solving this properly:

  1. Add @enum {number} to export const A. This isn't as good as it being a real TypeScript enum, it basically just declares type A = number but it fixes the error.
  2. Add a /// <reference types="..." /> to the JS file when using --target deno so that Deno can pick up the proper type declarations in the first place.

Probably we should do both, since the JSDoc declarations should work if necessary (e.g. --no-typescript is passed) but then the TypeScript declarations should be used if available.

Yes it's in Deno, I didn't think it's related thank fo investigating, is Deno behavior correct here or should I open a bug report ?

No, Deno's behaviour is correct. One of their goals is not to magically look up extra files since that might be wasting extra network requests, and so they differ from tsc here. tsc gives the same error if you delete the .d.ts file.