Use private constructors in type definitions of structs without an exported constructor #4282
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
Motivation
A simple empty struct was previously typed as follows:
This typing is incorrect. In JavaScript, a missing constructor is equivalent to an empty constructor.
Example:
So the above type for
Foois actually just a short form for this:Obviously, this is not correct. The
Fooclass is not supported to be instantiate-able using the class constructor. In debug mode, WBG even generates a constructor that always throws.Changes in this PR
This PR solves this problem by adding a
private constructorfor structs with a#[wasm_bindgen(constructor)]. E.g. the aboveFoostruct would get this type definitions:A private constructor in TS declares the constructor as inaccessible to anyone besides the class itself. In particular, a private constructor prevents users in TypeScript from:
new Foo().class Bar extends Foo {}.Fooin generic functions that require a constructor.See this TS playground for proof.
With those changes, the type definitions now accurately represent the correct usage of class
Fooand correctly cause errors on incorrect usage.Is this a breaking change?
Probably not.
Since this is a type-only change, nothing will break at runtime (more than it already is). Users using the implicitly defined constructor most likely isn't intended by WBG since WBG even generates a constructor that always throws in debug mode to prevent exactly this.
So this PR will at most cause new TS compiler errors for incorrect code. From that perspective, I would argue that this PR is not a breaking change.