From 13d119c5812615b702350c99e03f957c8317d618 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Tue, 26 Mar 2024 13:06:13 -0700 Subject: [PATCH 1/3] Add docs for ExternalDartReference This type exists in 3.4 onwards but isn't a JS type. See https://github.com/dart-lang/sdk/issues/55187 for more details on what the type is. --- src/content/interop/js-interop/js-types.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/content/interop/js-interop/js-types.md b/src/content/interop/js-interop/js-types.md index 2d89deb661..7f0f473b7f 100644 --- a/src/content/interop/js-interop/js-types.md +++ b/src/content/interop/js-interop/js-types.md @@ -38,6 +38,15 @@ JS types form a natural type hierarchy: You can find the definition of each type in the [`dart:js_interop` API docs]. +From Dart 3.4 onwards, there also exists one type in `dart:js_interop` that can +be used but is *not* a JS type called `ExternalDartReference`. + +Both `JSBoxedDartObject` and `ExternalDartReference` pass opaque references to +Dart `Object`s through JavaScript. However, `JSBoxedDartObject` wraps the opaque +reference in a JavaScript object, while `ExternalDartReference` is the reference +itself and therefore is not a JS type. Use `ExternalDartReference` where +performance is needed and `JSBoxedDartObject` where a JS type is needed. + {% comment %} TODO (srujzs): Should we add a tree diagram instead for JS types? {% endcomment %} @@ -73,7 +82,7 @@ Generally, the conversion table looks like the following:
| JS type | Dart type | -|-------------------------------------|------------------------------------------| +| ----------------------------------- | ---------------------------------------- | | `JSNumber`, `JSBoolean`, `JSString` | `num`, `int`, `double`, `bool`, `String` | | `JSExportedDartFunction` | `Function` | | `JSArray` | `List` | @@ -103,8 +112,8 @@ specific conversion function for more details. In order to ensure type safety and consistency, the compiler places requirements on what types can flow into and out of JS. Passing arbitrary Dart values into JS is not allowed. Instead, the compiler requires users to use a compatible interop -type or a primitive, which would then be implicitly converted by the compiler. -For example, these would be allowed: +type, `ExternalDartReference`, or a primitive, which would then be implicitly +converted by the compiler. For example, these would be allowed: ```dart tag=good @JS() @@ -123,6 +132,11 @@ extension type InteropType(JSObject _) implements JSObject {} external InteropType get interopType; ``` +```dart tag=good +@JS() +external void externalDartReference(ExternalDartReference _); +``` + Whereas these would return an error: ```dart tag=bad From 34438fffbf47ed9f6540d3c9d7b8907eda790e09 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Fri, 29 Mar 2024 17:00:49 -0700 Subject: [PATCH 2/3] Handle review comments --- src/content/interop/js-interop/js-types.md | 41 ++++++++++++++-------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/content/interop/js-interop/js-types.md b/src/content/interop/js-interop/js-types.md index 7f0f473b7f..3838d59210 100644 --- a/src/content/interop/js-interop/js-types.md +++ b/src/content/interop/js-interop/js-types.md @@ -35,18 +35,13 @@ JS types form a natural type hierarchy: - JS typed arrays like `JSUint8Array` - `JSBoxedDartObject`, which allows users to box and pass Dart values opaquely within the same Dart runtime + - From Dart 3.4 onwards, the type `ExternalDartReference` in + `dart:js_interop` also allows users to pass Dart values opaquely, but is + *not* a JS type. Learn more about the tradeoffs between each option + [here](#jsboxeddartobject-vs-externaldartreference). You can find the definition of each type in the [`dart:js_interop` API docs]. -From Dart 3.4 onwards, there also exists one type in `dart:js_interop` that can -be used but is *not* a JS type called `ExternalDartReference`. - -Both `JSBoxedDartObject` and `ExternalDartReference` pass opaque references to -Dart `Object`s through JavaScript. However, `JSBoxedDartObject` wraps the opaque -reference in a JavaScript object, while `ExternalDartReference` is the reference -itself and therefore is not a JS type. Use `ExternalDartReference` where -performance is needed and `JSBoxedDartObject` where a JS type is needed. - {% comment %} TODO (srujzs): Should we add a tree diagram instead for JS types? {% endcomment %} @@ -81,7 +76,7 @@ Generally, the conversion table looks like the following:
-| JS type | Dart type | +| Interop type | Dart type | | ----------------------------------- | ---------------------------------------- | | `JSNumber`, `JSBoolean`, `JSString` | `num`, `int`, `double`, `bool`, `String` | | `JSExportedDartFunction` | `Function` | @@ -89,6 +84,7 @@ Generally, the conversion table looks like the following: | `JSPromise` | `Future` | | Typed arrays like `JSUint8Array` | Typed lists from `dart:typed_data` | | `JSBoxedDartObject` | Opaque Dart value | +| `ExternalDartReference` | Opaque Dart value | {:.table .table-striped}
@@ -254,9 +250,22 @@ to interop members or distinguish between JS `null` and `undefined` values, but this will likely change in the future. See [#54025] for more details. ::: -{% comment %} -TODO: add links (with stable) when ready: -{% endcomment %} +## `JSBoxedDartObject` vs `ExternalDartReference` + +From Dart 3.4 onwards, both [`JSBoxedDartObject`] and [`ExternalDartReference`] +can be used to pass opaque references to Dart `Object`s through JavaScript. +However, `JSBoxedDartObject` wraps the opaque reference in a JavaScript object, +while `ExternalDartReference` is the reference itself and therefore is not a JS +type. + +Use `JSBoxedDartObject` if you need a JS type or if you need extra checks to +make sure Dart values don't get passed to another Dart runtime. For example, if +the Dart object needs to be placed in a `JSArray` or passed to an API that +accepts a `JSAny`, use `JSBoxedDartObject`. Use `ExternalDartReference` +otherwise as it will be faster. + +See [`toExternalReference`] and [`toDartObject`] to convert to and from an +`ExternalDartReference`. [`dart:js_interop`]: https://api.dart.dev/dev/dart-js_interop/dart-js_interop-library.html [`external`]: https://dart.dev/language/functions#external @@ -266,4 +275,8 @@ TODO: add links (with stable) when ready: [`instanceOfString`]: https://api.dart.dev/dev/dart-js_interop/JSAnyUtilityExtension/instanceOfString.html [`isA`]: https://api.dart.dev/dev/dart-js_interop/JSAnyUtilityExtension/isA.html [#4841]: https://github.com/dart-lang/linter/issues/4841 -[#54025]: https://github.com/dart-lang/sdk/issues/54025 \ No newline at end of file +[#54025]: https://github.com/dart-lang/sdk/issues/54025 +[`JSBoxedDartObject`]: https://api.dart.dev/main/dart-js_interop/JSBoxedDartObject-extension-type.html +[`ExternalDartReference`]: https://api.dart.dev/main/dart-js_interop/ExternalDartReference-extension-type.html +[`toExternalReference`]: https://api.dart.dev/main/dart-js_interop/ObjectToExternalDartReference/toExternalReference.html +[`toDartObject`]: https://api.dart.dev/main/dart-js_interop/ExternalDartReferenceToObject/toDartObject.html \ No newline at end of file From 0583e58fd67c5af3f67032ca3fb7ef125ed4376f Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Mon, 1 Apr 2024 14:07:52 -0700 Subject: [PATCH 3/3] Amend links and change interop type title --- src/content/interop/js-interop/js-types.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/interop/js-interop/js-types.md b/src/content/interop/js-interop/js-types.md index b84aefceb2..c7e96f0388 100644 --- a/src/content/interop/js-interop/js-types.md +++ b/src/content/interop/js-interop/js-types.md @@ -76,7 +76,7 @@ Generally, the conversion table looks like the following:
-| Interop type | Dart type | +| `dart:js_interop` type | Dart type | | ----------------------------------- | ---------------------------------------- | | `JSNumber`, `JSBoolean`, `JSString` | `num`, `int`, `double`, `bool`, `String` | | `JSExportedDartFunction` | `Function` | @@ -276,7 +276,7 @@ See [`toExternalReference`] and [`toDartObject`] to convert to and from an [`isA`]: {{site.dart-api}}/{{site.sdkInfo.channel}}/dart-js_interop/JSAnyUtilityExtension/isA.html [#4841]: https://github.com/dart-lang/linter/issues/4841 [#54025]: https://github.com/dart-lang/sdk/issues/54025 -[`JSBoxedDartObject`]: https://api.dart.dev/main/dart-js_interop/JSBoxedDartObject-extension-type.html -[`ExternalDartReference`]: https://api.dart.dev/main/dart-js_interop/ExternalDartReference-extension-type.html -[`toExternalReference`]: https://api.dart.dev/main/dart-js_interop/ObjectToExternalDartReference/toExternalReference.html -[`toDartObject`]: https://api.dart.dev/main/dart-js_interop/ExternalDartReferenceToObject/toDartObject.html \ No newline at end of file +[`JSBoxedDartObject`]: {{site.dart-api}}/{{site.sdkInfo.channel}}/dart-js_interop/JSBoxedDartObject-extension-type.html +[`ExternalDartReference`]: {{site.dart-api}}/{{site.sdkInfo.channel}}/dart-js_interop/ExternalDartReference-extension-type.html +[`toExternalReference`]: {{site.dart-api}}/{{site.sdkInfo.channel}}/dart-js_interop/ObjectToExternalDartReference/toExternalReference.html +[`toDartObject`]: {{site.dart-api}}/{{site.sdkInfo.channel}}/dart-js_interop/ExternalDartReferenceToObject/toDartObject.html \ No newline at end of file