-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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 null
to argument types of optional parameters
#4188
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Missing a changelog entry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nit left, otherwise this LGTM.
I just realized that return and argument types not being the same is a problem for generated getter-setter pairs. |
@daxpedda You know when we talked about |
Okay, there is one more thing I need to put out there. I noticed that one of our TS tests failed. This test defined Rust struct like this: #[wasm_bindgen]
pub struct Fields {
pub hallo: Option<bool>,
pub spaceboy: bool,
} And checked whether this type checks: import * as wbg from '../pkg/typescript_tests';
const fields: wbg.Fields = { spaceboy: true, free: () => { } }; Note that the assigned object has no This previously worked, because the generated type of the class Fields {
hallo?: boolean;
spaceboy: boolean;
free(): void;
} Note that This is no longer the case. Since fields of type class Fields {
get hallo(): boolean | undefined;
set hallo(value: boolean | null | undefined);
spaceboy: boolean;
free(): void;
} The important bit here is that getters and setters can never be omitted. This means that the above TS code no longer compiles, since the I am brining this up here, because this might break (type-checked) user code, just like it broke the test. However, I am not too concerned about this. I just wanted to mention all this in case someone opens an issue about this. |
I'm a bit confused, why is this happening? I can't seem to find the code changes that cause these to be getters/setters instead of fields. If this is caused by another PR then which and how? |
#4202 implemented this. You can see similar behavior in the tests of that PR in the In JS, getters and setter can return/accept data of different types, so the general way to write a getter-setter pair is get prop(): GetType;
set prop(value: SetType); But since prop: GetAndSetType; // assumes GetAndSetType == GetType == SetType So when it comes to typing properties, the field syntax is just a common special case. Since the getter type and setter type of |
Ah, completely overlooked that, thank you!
I'm concerned that this is exactly whats happening. I wish I could get more sign-offs on this, but unfortunately I don't expect any. I'm gonna ask around and see if I get any responses before merging it. |
Yeah, the fact that we had a test for this is a bad omen. So a third opinion would be nice. However, the good news is that this at most causes type errors in code that misuses classes as interfaces. And we recently talked about type errors not being breaking changes on the side, so maybe it's not an issue at all. |
In theory this is definitely not an issue, especially because it would be an API misuse. But my concern is in practice, I don't want to break maybe a whole ecosystem out there without even a warning. |
In general, we should probably add docs clarifying what guarantees WBG makes. Also, maybe something like an RC/nightly/canary process could help? If nothing else, maybe a week or two before a new release, make an RC and a public call for testing, so people can report bugs before the actual release is made. No idea to what level cargo/crates.io supports this though (I'm still somewhat new to Rust). I'm just speaking from my experience in the npm ecosystem. |
These kind of docs are in great need for improvement indeed, any help here would be appreciated!
Would be nice for releases like this. Unfortunately the maintainer bandwidth isn't really there for that. |
Then I'll try to write down TypeScript guarantees somewhere the next few days.
Are there no automated tools for that in Rust? E.g. there's changesets which automates changelog creating, publishing, versioning etc. for JS/TS monorepos. Admittedly, I only worked on projects that use |
While making a new |
Wouldn't a beta release process ease that burden? I mean, if something breaks, you'll get reports anyway, but there is less pressure to fix it in a beta release (and fewer duplicates), since it doesn't affect the whole ecosystem. As I see it, the main thing you buy yourself with a beta release is time and ease of mind. If the beta is broken and you're on vacation, most users won't even notice since they're on the latest stable release. Just fix it a month later (or wait until someone does a PR), make another beta, and repeat until it passes the scream test. This might slow down releases, but people that need the latest features can use beta and bear the cutting edge. But maybe my view on this all is a bit naive since I've been in the position of maintaining a project of the size and reach of WBG. |
No you are absolutely right, which is why I said earlier I should get my priorities straight 😅! But just as a reality check: I don't believe a lot of users will get reached by a beta. Unfortunately is is incompatible with any other dependency. So in practice, users will have to use I sent you a private Email about further discussing stuff like that, did you get it? |
Straight to spam. Thanks gmail 😆 |
All functions with
Option<T>
arguments take bothundefined
andnull
and generally treat them as equivalent (seeisLikeNone
). Despite bothundefined
andnull
being accepted, the generated type definitions only allowedundefined
. Example:This is unnecessarily restrictive, as
echo(null)
would also work (seeisLikeNone
) and returnundefined
just likeecho(undefined)
. This also results in worse ergonomics as many DOM APIs returnvalue | null
(e.g.textContent
), which currently requires dev to unnecessarily mapnull
toundefined
(e.g.echo(element.textContent ?? undefined)
).To bring the generated type definitions in line with the actual runtime behavior of the JS glue code, I changed the type of optional parameters from
T | undefined
toT | undefined | null
. E.g. the function signature ofecho
is the following with this PR:This accurately represent the runtime behavior of the function and results in better ergonomics.
Note: This PR only affects function arguments. The return type is still
T | undefined
, as it should be.Tests
To test that this (and other features I have planned) are implemented correctly, I added a single large test file:
echo.rs
. This test file just contains echo/identity functions for various types to check the glue code of various input/output types.