-
Notifications
You must be signed in to change notification settings - Fork 205
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
Typings is a package that transpiles TypeScript to Dart and enable directly use of NPM packages. Lets make it sound #2995
Comments
Disclaimer, I don't actually know anything about Dart JS interop.
Probably. Providing a static Dart view on a different/foreign object representation is pretty much what inline classes are designed for. It should be usable for anything like this.
That's harder. Dart currently requires the target of a
By "translated", do you mean "converted to" or "interpreted as"? If the former, I'd convert Promises to futures, and vice-versa, should be doable.
The usual Dart approach to union types is to use
Possibly not. The bigger issue is that interface properties can be non-readonly, Dart records are unmodifiable. It's probably possible to work around that (use a record containing mutable value wrappers), but it's not as direct.
Naming them differently, but that's hard to automate. var action = {while: "I'm OK", do: "Stay OK"}; This seems to be valid TS, because object properties are allowed to be reserved words. Both |
Agreeing with @lrhn, I'll add a few extra comments. @jodinathan wrote:
That is certainly also what I would expect. The type systems are very different, and even small differences can be hard to bridge when it comes to global properties like static typing. Computer scientists and language designers have done many things over a period of decades to make static type checking modular. So it could be claimed that static typing is a local property. However, that's only because we are adding a lot of declared types to programs (such as formal parameter types and return types of functions, or types of instance variables, etc). It is probably necessary to deal with the declared as well as the computed types in a global manner in order to find "an equivalent typing" using a different type system. That said, I'd be really surprised if any such "equivalent typing" even exists, in all but the most trivial cases. However, we can use some systematic techniques to express a compatible, but less precise, typing. For instance, we could start by using Next step could be to handle some particularly safe cases, e.g., by translating basic types of TypeScript to Dart types. Further steps would provide a non- There is ongoing work on a new version of JS interop (@srujzs and @joshualitt are at the core of this work), and they plan to use specialized Dart types to provide access to JS objects in a Dart program, based on special "native" classes like I think this new approach to JS interop would be a very useful component of your effort with Typings. Basically, I think you would be able to generate code using the new JS interop from the given The ability to make the transition from a Dart
The plan is that the new JS interop will use inline classes to provide a statically typed way to access JS objects, and I'd assume that Typings would provide support for generating JS interop code which would otherwise be created in some other way (e.g., it could be handwritten, based on an informal type analysis of the underlying JS code). Of course, this doesn't eliminate the difficulties I mentioned above, based on the fact that the type systems are deeply different. But it does provide a well-understood, widely used framework to express the chosen Dart typing which is the result of that difficult type-system-to-type-system translation process.
The exact same question has been raised in connection with the new JS interop. Some possible designs were discussed last year, e.g., in #2150. The basic idea was that it should be possible to satisfy the requirements for being the iterable object of a 'for-in' statement without actually implementing We used to have a structural (typeless) approach: Any object with an We could also have a special exception for inline classes (so the iterable object could be an I don't think there is an easy way out here, other than implementing a getter in the inline class that actually returns an object of type However, there was a considerable amount of interest in the topic, so we might be able to come up with a better approach, just not in the short term.
I think the fact that the new JS interop uses
That was the hard part. ;-) |
@eernstg @lrhn There is already some logic to try to make the transpilled Dart a sound code. For example, overloaded methods become a
Becomes a class Document {
({
/// Creates an instance of the element for the specified tag.
/// @param tagName The name of an element.
K$ Function<K$ extends _i3.Element>(
HTMLElementTagNameMap<K$> tagName, [
_i3.ElementCreationOptions? options,
]) $1,
/// Creates an instance of the element for the specified tag.
_i3.HTMLElement Function(
_i2.String tagName, [
_i3.ElementCreationOptions? options,
]) $2,
}) get createElement => (
$1: _createElement$1,
$2: _createElement$2,
);
} In an attempt to make it as sound as I can I make it use inference for the first version final div = js.document.createElement.$1(js.HTMLElementTagNameMap.div);
// div is of type HTMLDivElement, thanks to inference The idea is not to transpile an exact version of the TS code, but a sound Dart version and let the inner code do the JS magic. For example, we could do some trick to make Union types sound in Dart: interface Foo {
foo(bar: A | B): void;
} The however, we could transpile the union to a record and check for non null in the call: class Foo {
void foo(({A? a, B? b}) bar) {
js.callMethod(this, 'foo', [ bar.a ?? bar.b ]);
}
} Then the user will have a sound signature to use: final f = Foo();
f.foo((a : A())); Adding a condition within Foo().foo(A()); // there isn't a record or condition in the compiled JS Then we would be ok regarding performance, however, it would still remain the question if this is the best approach for the users. Please, take a look at the Wiki as it contains some of the "tricks" I am already doing to try to make it sound.Would be nice to know if the current approach makes sense or what I could/should change.
Weird. Can't we already use
This seems to be the best approach. |
Thanks for sharing about your current efforts in package:typings! In case you are not aware, our prior work in js_facade_gen is very related and may provide some insights. js_facade_gen uses the TS parser to read in .d.ts files and generate Dart JS-interop facade code. This predates The team that worked on that package also faced similar questions as those you are addressing in package:typings. For example, they used a least-upper-bound to resolve unions and intersection types (see merge.ts). Note also that many of these questions also exist since the early days of It's worth noting that there are scenarios were we couldn't pick a single strategy in the past. For example,
Great questions. This is changing in part due to the need to be more clear about the Dart/JS boundary. We are working to make JS interop work both on JS-based backends (DDC and dart2js) and in the wasmGC backend (dart2wasm). Without WASM, it was not as noticeable, and we felt OK conflating the types: int vs JSNumber were represented by the same value, so we didn't bother making a distinction. With the WASMGC backend this is changing, we have separate heaps and we need to better map the boundary. Moreover, we had cases in the past where conflation was problematic. For example, we allowed That said, we know this would be a big regression in ergonomics if you have to write |
Hi,
I am the author of js_bindings and now I've published Typings.
The package transpiles a TypeScript declaration file (
.d.ts
) to Dart JS interop.It will replace
js_bindings
as it has full ES2023 interop.The transpilling process can be done automatically to any NPM package that has a TS declaration file and also exposes a helper function that injects the JS into the DOM.
It basically allows a developer to use NPM packages without the burden of manually generate the JS interop nor having to add the script tag in the HTML file.
The builder tries to understand the TS code in an attempt to transpile sound Dart code.
However, this is no simple task.
Some questions:
Array
or[Symbol.iterator]
loopable?I already currently address some of these questions and you can know more in the README and the WIP Wiki.
As it is a new package and intended to use full Dart 3, we can make tests to find the best way to transpile the code before releasing an stable version.
The text was updated successfully, but these errors were encountered: