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

Add a dart:js_interop API that can determine if an Object is a JS value #56905

Open
srujzs opened this issue Oct 16, 2024 · 6 comments
Open

Add a dart:js_interop API that can determine if an Object is a JS value #56905

srujzs opened this issue Oct 16, 2024 · 6 comments
Assignees
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-js-interop Issues that impact all js interop

Comments

@srujzs
Copy link
Contributor

srujzs commented Oct 16, 2024

Historically, it was common for users to treat JS values through interop as Dart types and not JS types, mainly because the concept of "JS types" did not exist yet. So, values may flow through as Object or dynamic to other parts of code. This code may accept both a Dart and a JS value, making it difficult to determine how to treat such a value without some way of distinguishing the two runtimes.

The canonical way to type-check Dart objects is to use is, but we don't want users using that if it's a JS value, as it may give inconsistent values. This is partially why we have the invalid_runtime_check_with_js_interop_types lint.

The canonical way to type-check JS values is to use isA, but that requires a cast to JSAny in the first place. This cast will always succeed when compiling to JS (because it's Object under-the-hood there), but may fail when compiling to Wasm (because it's JSValue). This is our best option today.

So, to determine how to type-check a given Object, it is useful to know whether it's a JS value in the first place. One such mechanism is a compiler-specific external patched API in dart:js_interop.

Some quirks that we might come across:

  • Primitive types (String, int/double/num, bool) are both Dart and JS values when compiling to JS. This is not true when compiling to Wasm. We may want to always treat them as JS values for the sake of this API, but users should be aware that they should still type-check for the Dart primitive types when this API returns false so that they handle the Wasm case correctly.
  • Dart functions are JS functions in DDC, so the implementation should use the type system internals to differentiate them instead of interop.
  • Inconsistencies in our internal type system checks. Hopefully this should be fine in most realistic use cases, but we've seen edge-cases before e.g. DDC treating prototypes of compiled Dart objects as Dart objects whereas dart2js and dart2wasm do not. I expect dart2wasm should generally have no issues with this check due to the boxing.
  • We may want to modify the invalid_runtime_check_with_js_interop_types check to account for this new API e.g. pointing users to this API when they do a is JSAny check.
@srujzs srujzs added web-js-interop Issues that impact all js interop area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. labels Oct 16, 2024
@srujzs srujzs changed the title Add a dart:js_interop API that can determine if a Object is a JS value Add a dart:js_interop API that can determine if an Object is a JS value Oct 16, 2024
@srujzs srujzs self-assigned this Jan 18, 2025
@srujzs srujzs marked this as a duplicate of #59932 Jan 18, 2025
@gmpassos
Copy link
Contributor

gmpassos commented Jan 18, 2025

Any update on this?

@gmpassos
Copy link
Contributor

FYI: @kevmoo @mit-mit

We urgently need something like the extension below, with official support for each platform:

extension ObjectToJSAnyNullableExtension on Object? {
  bool get isJSAny;
  bool get isJSObject;
}

NOTE: After discussing this issue with other developers, we concluded that, without a secure way to cast Object to JSAny, the new dart:js_interop is not stable for real-world use cases.

@kevmoo
Copy link
Member

kevmoo commented Jan 20, 2025

@srujzs is the expert here. I will make sure we follow-up this week.

@gmpassos
Copy link
Contributor

@srujzs is the expert here. I will make sure we follow-up this week.

Thanks for the quick response

@srujzs
Copy link
Contributor Author

srujzs commented Jan 22, 2025

I want to get this done before the next stable, for both the JS compilers and dart2wasm.

I don't believe we need isJSObject as long as we can check if something is a JS value. This would then allow you to cast to JSAny? and safely type-check via isA<JSObject>.

@gmpassos
Copy link
Contributor

I agree that isJSObject is not mandatory. However, since most cases of using JSAny.isA<T>() involve a T that is not a primitive, isJSObject can be very useful.

It also provides an opportunity for an optimized implementation of isJSObject. Additionally, it is easier to ensure that an Object is a JSObject, as the primitive implementations of JSAny can be ambiguous depending on the platform.

Therefore, it is much easier to implement isJSObject in cases where isJSAny becomes ambiguous.

I have internally implemented a bool? isJSAny that returns null in cases where the detection is ambiguous. However, for isJSObject, there are no ambiguous cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-web Use area-web for Dart web related issues, including the DDC and dart2js compilers and JS interop. web-js-interop Issues that impact all js interop
Projects
Status: No status
Development

No branches or pull requests

3 participants