From 540db9938bf126abdda06c42c7430f9a27991386 Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Tue, 7 Jan 2025 17:36:05 +0800 Subject: [PATCH] Clean up and format JS interop usage doc --- src/content/interop/js-interop/mock.md | 1 + src/content/interop/js-interop/usage.md | 417 +++++++++++++----------- 2 files changed, 227 insertions(+), 191 deletions(-) diff --git a/src/content/interop/js-interop/mock.md b/src/content/interop/js-interop/mock.md index 7b772fee1c..d3dde68707 100644 --- a/src/content/interop/js-interop/mock.md +++ b/src/content/interop/js-interop/mock.md @@ -1,5 +1,6 @@ --- title: How to mock JavaScript interop objects +description: Learn how to mock JS interop objects in Dart for testing. --- In this tutorial, you'll learn how to mock JS objects so that you can test diff --git a/src/content/interop/js-interop/usage.md b/src/content/interop/js-interop/usage.md index b5a0dae105..9cf02b7a15 100644 --- a/src/content/interop/js-interop/usage.md +++ b/src/content/interop/js-interop/usage.md @@ -4,41 +4,47 @@ description: How to declare and use JS interop members. --- JS interop provides the mechanisms to interact with JavaScript APIs from Dart. -It allows you to invoke these APIs and interact with the values that you get -from them using an explicit, idiomatic syntax. - -Typically, you access a JavaScript API by making it available somewhere within -the [global JS scope]. To call and receive JS values from this API, you use -[`external` interop members](#interop-members). In order to construct and -provide types for JS values, you use and declare -[interop types](#interop-types), which also contain interop members. To pass -Dart values like `List`s or `Function` to interop members or convert from JS -values to Dart values, you use [conversion functions] unless the interop member -[contains a primitive type]. +It allows you to invoke these APIs and interact with the values that +you get from them using an explicit, idiomatic syntax. + +Typically, you access a JavaScript API by making it available +somewhere within the [global JS scope][]. +To call and receive JS values from this API, +you use [`external` interop members](#interop-members). +To construct and provide types for JS values, you use and declare +[interop types](#interop-types), which also contain interop members. +To pass Dart values like a `List` or `Function` to interop members or +convert from JS values to Dart values, you use [conversion functions][] unless +the interop member [contains a primitive type][]. + +[global JS scope]: https://developer.mozilla.org/docs/Glossary/Global_scope +[conversion functions]: /interop/js-interop/js-types#conversions +[contains a primitive type]: /interop/js-interop/js-types#requirements-on-external-declarations-and-function-tojs ## Interop types -When interacting with a JS value, you need to provide a Dart type for it. You -can do this by either using or declaring an interop type. Interop types are -either a ["JS type"] provided by Dart or an [extension type] wrapping an interop -type. +When interacting with a JS value, you need to provide a Dart type for it. +You can do this by either using or declaring an interop type. +Interop types are either a ["JS type"][] provided by Dart or +an [extension type][] wrapping an interop type. -Interop types allow you to provide an interface for a JS value and lets you -declare interop APIs for its members. They are also used in the signature of -other interop APIs. +Interop types allow you to provide an interface for a JS value and +let you declare interop APIs for its members. +They're also used in the signature of other interop APIs. ```dart extension type Window(JSObject _) implements JSObject {} ``` -`Window` is an interop type for an arbitrary `JSObject`. There is no [runtime -guarantee][] that `Window` is actually a JS [`Window`]. There also is no conflict -with any other interop interface that is defined for the same value. If you want -to check that `Window` is actually a JS `Window`, you can -[check the type of the JS value through interop]. +`Window` is an interop type for an arbitrary `JSObject`. +There's no [runtime guarantee][] that `Window` is actually a JS [`Window`][]. +There also is no conflict with any other interop interface that +is defined for the same value. +If you want to check that `Window` is actually a JS `Window`, +you can [check the type of the JS value through interop][]. -You can also declare your own interop type for the JS types Dart provides by -wrapping them: +You can also declare your own interop type for the JS types that +Dart provides by wrapping them: ```dart extension type Array._(JSArray _) implements JSArray { @@ -46,23 +52,37 @@ extension type Array._(JSArray _) implements JSArray { } ``` -In most cases, you will likely declare an interop type using `JSObject` as the -[representation type] because you're likely interacting with JS objects which -don't have an interop type provided by Dart. +In most cases, you'll likely declare an interop type using +`JSObject` as the [representation type][], because you're likely +interacting with JS objects which don't have an interop type provided by Dart. -Interop types should also generally [implement] their representation type so -that they can be used where the representation type is expected, like in many -APIs in [`package:web`]. +Interop types should also generally [implement][] their representation type so +that they can be used where the representation type is expected, +like in many APIs provided by [`package:web`][]. + +["JS type"]: /interop/js-interop/js-types +[extension type]: /language/extension-types +[`Window`]: https://developer.mozilla.org/docs/Web/API/Window +[runtime guarantee]: /language/extension-types#type-considerations +[check the type of the JS value through interop]: /interop/js-interop/js-types#compatibility-type-checks-and-casts +[representation type]: /language/extension-types#declaration +[implement]: /language/extension-types#implements +[`package:web`]: {{site.pub-pkg}}/web ## Interop members -[`external`] interop members provide an idiomatic syntax for JS members. They -allow you to write a Dart type signature for its arguments and return value. The -types that can be written in the signature of these members have [restrictions]. +[`external`][] interop members provide an idiomatic syntax for JS members. +They allow you to write a Dart type signature for its +arguments and return value. +The types that can be written in the signature of +these members have [restrictions][]. The JS API the interop member corresponds to is determined by a combination of where it's declared, its name, what kind of Dart member it is, and any [renames](#js). +[`external`]: /language/functions#external +[restrictions]: /interop/js-interop/js-types#requirements-on-external-declarations-and-function-tojs + ### Top-level interop members Given the following JS members: @@ -87,16 +107,18 @@ external set name(String value); external bool isNameEmpty(); ``` -Here, there exists a property `name` and a function `isNameEmpty` that are -exposed in the global scope. To access them, you use top-level interop members. -To get and set `name`, you declare and use an interop getter and setter with the -same name. To use `isNameEmpty`, you declare and call an interop function with -the same name. You can declare top-level interop getters, setters, methods, and -fields. Interop fields are equivalent to getter and setter pairs. +Here, there exists a property `name` and a function `isNameEmpty` that +are exposed in the global scope. +To access them, you use top-level interop members. +To get and set `name`, declare and use +an interop getter and setter with the same name. +To use `isNameEmpty`, declare and call an interop function with the same name. +You can declare top-level interop getters, setters, methods, and fields. +Interop fields are equivalent to getter and setter pairs. Top-level interop members must be declared with a [`@JS()`](#js) annotation to -distinguish them from other `external` top-level members, like those that can be -written using `dart:ffi`. +distinguish them from other `external` top-level members, +like those that can be written using `dart:ffi`. ### Interop type members @@ -162,17 +184,19 @@ Within an interop type, you can declare several different types of - **Constructors**. When called, constructors with only positional parameters create a new JS object whose constructor is defined by the name of the - extension type using `new`. For example, calling `Time(0, 0)` in Dart will - generate a JS invocation that looks like `new Time(0, 0)`. Similarly, calling - `Time.onlyHours(0)` will generate a JS invocation that looks like - `new Time(0)`. Note that the JS invocations of the two constructors follow the - same semantics, regardless of whether they're given a Dart name or if they are - a factory. - - - **Object literal constructors**. It is useful sometimes to create a JS - [object literal] that simply contains a number of properties and their - values. In order to do this, you declare a constructor with only named - parameters, where the names of the parameters will be the property names: + extension type using `new`. + For example, calling `Time(0, 0)` in Dart generates a JS invocation that + looks like `new Time(0, 0)`. Similarly, calling + `Time.onlyHours(0)` generates a JS invocation that looks like `new Time(0)`. + Note that the JS invocations of the two constructors follow the + same semantics, regardless of whether they're + given a Dart name or if they're a factory. + + - **Object literal constructors**. It's sometimes useful to + create a JS [object literal][] that simply contains a + number of properties and their values. + In order to do this, declare a constructor with only named + parameters, where the names of the parameters match the property names: ```dart extension type Options._(JSObject o) implements JSObject { @@ -182,10 +206,12 @@ Within an interop type, you can declare several different types of } ``` - A call to `Options(a: 0, b: 1)` will result in creating the JS object - `{a: 0, b: 1}`. The object is defined by the invocation arguments, so - calling `Options(a: 0)` would result in `{a: 0}`. You can get or set the - properties of the object through `external` instance members. + A call to `Options(a: 0, b: 1)` results in + creating the JS object `{a: 0, b: 1}`. + The object is defined by the invocation arguments, so + calling `Options(a: 0)` results in `{a: 0}`. + You can get or set the properties of the object through + `external` instance members. :::warning Before Dart 3.3.1, object literal constructors required a @@ -193,15 +219,16 @@ Within an interop type, you can declare several different types of To learn more, check out [`dart-lang/sdk#54801`][54801]. ::: -- **`static` members**. Like constructors, these members use the name of the - extension type to generate the JS code. For example, calling - `Time.getTimeDifference(t1, t2)` will generate a JS invocation that looks like - `Time.getTimeDifference(t1, t2)`. Similarly, calling `Time.dinnerTime` will - result in a JS invocation that looks like `Time.dinnerTime`. Like top-levels, +- **`static` members**. Like constructors, static members use + the name of the extension type to generate the JS code. For example, + calling `Time.getTimeDifference(t1, t2)` generates a JS invocation that + looks like `Time.getTimeDifference(t1, t2)`. + Similarly, calling `Time.dinnerTime` results in a JS invocation that + looks like `Time.dinnerTime`. Like top-levels, you can declare `static` methods, getters, setters, and fields. -- **Instance members**. Like with other Dart types, these members require an - instance in order to be used. These members get, set, or invoke properties on +- **Instance members**. Like with other Dart types, instance members require + an instance to be used. These members get, set, or invoke properties on the instance. For example: ```dart @@ -213,16 +240,20 @@ Within an interop type, you can declare several different types of print(time.isDinnerTime()); // true ``` - The call to `dinnerTime.hours` gets the value of the `hours` property of - `dinnerTime`. Similarly, the call to `time.minutes=` sets the value of the - `minutes` property of time. The call to `time.isDinnerTime()` calls the - function in the `isDinnerTime` property of `time` and returns the value. - Like top-levels and `static` members, you can declare instance methods, - getters, setters, and fields. - -- **Operators**. There are only two `external` interop operators allowed in - interop types: `[]` and `[]=`. These are instance members that match the - semantics of JS' [property accessors]. For example, you can declare them like: + The call to `dinnerTime.hours` gets the value of + the `hours` property of `dinnerTime`. + Similarly, the call to `time.minutes=` sets the value of + the `minutes` property of time. + The call to `time.isDinnerTime()` calls the function in + the `isDinnerTime` property of `time` and returns the value. + Like top-levels and `static` members, you can declare + instance methods, getters, setters, and fields. + +- **Operators**. There are only two `external` interop operators + allowed in interop types: `[]` and `[]=`. + These are instance members that + match the semantics of JS' [property accessors][]. + For example, you can declare them like: ```dart extension type Array(JSArray _) implements JSArray { @@ -232,16 +263,23 @@ Within an interop type, you can declare several different types of ``` Calling `array[i]` gets the value in the `i`th slot of `array`, and - `array[i] = i.toJS` sets the value in that slot to `i.toJS`. Other JS - operators are exposed through [utility functions] in `dart:js_interop`. + `array[i] = i.toJS` sets the value in that slot to `i.toJS`. + Other JS operators are exposed by [utility functions][] in `dart:js_interop`. Lastly, like any other extension type, you're allowed to declare any -[non-`external` members] in the interop type. `isMidnight` is one such example. +[non-`external` members][] in the interop type. +A boolean getter `isMidnight` that uses the interop values is one such example. + +[object literal]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Object_initializer +[54801]: {{site.repo.dart.sdk}}/issues/54801 +[property accessors]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Property_accessors#bracket_notation +[utility functions]: {{site.dart-api}}/dart-js_interop/JSAnyOperatorExtension.html +[non-`external` members]: /language/extension-types#members ### Extension members on interop types -You can also write `external` members in [extensions] of interop types. For -example: +You can also write `external` members in [extensions][] of interop types. +For example: ```dart extension on Array { @@ -249,44 +287,54 @@ extension on Array { } ``` -The semantics of calling `push` are identical to what it would have been if it -was in the definition of `Array` instead. Extensions can have `external` -instance members and operators, but cannot have `external` `static` members or -constructors. Like with interop types, you can write any non-`external` members -in the extension. These extensions are useful for when an interop type doesn't -expose the `external` member you need and you don't want to create a new interop -type. +The semantics of calling `push` are identical to what it would have been if +it was in the definition of `Array` instead. +Extensions can have `external` instance members and operators, but +can't have `external` `static` members or constructors. +Like with interop types, you can +write any non-`external` members in the extension. +These extensions are useful for when an interop type doesn't +expose the `external` member you need, and you don't want to +create a new interop type. + +[extensions]: /language/extension-methods ### Parameters `external` interop methods can only contain positional and optional arguments. -This is because JS members only take positional arguments. The one exception is -object literal constructors, where they can contain only named arguments. +This is because JS members only take positional arguments. +The one exception is object literal constructors, +where they can contain only named arguments. -Unlike with non-`external` methods, optional arguments do not get replaced with -their default value, but are instead omitted. For example: +Unlike with non-`external` methods, optional arguments don't get +replaced with their default value, but are instead omitted. +For example: ```dart external int push(JSAny? any, [JSAny? any2]); ``` -Calling `array.push(0.toJS)` in Dart will result in a JS invocation of -`array.push(0.toJS)` and *not* `array.push(0.toJS, null)`. This allows users to -not have to write multiple interop members for the same JS API to avoid passing -in `null`s. If you declare a parameter with an explicit default value, you will +Calling `array.push(0.toJS)` in Dart results in +a JS invocation of `array.push(0.toJS)` and *not* `array.push(0.toJS, null)`. +This allows users to not have to write multiple interop members for +the same JS API to avoid passing in `null`s. +If you declare a parameter with an explicit default value, you get a warning that the value will be ignored. ## `@JS()` -It is sometimes useful to refer to a JS property with a different name than the -one written. For example, if you want to write two `external` APIs that point to -the same JS property, you’d need to write a different name for at least one of -them. Similarly, if you want to define multiple interop types that refer to the -same JS interface, you need to rename at least one of them. Another example is -if the JS name cannot be written in Dart e.g. `$a`. +It's sometimes useful to refer to a JS property with +a different name than the one written. +For example, if you want to write two `external` APIs that +point to the same JS property, you'd need to +write a different name for at least one of them. +Similarly, if you want to define multiple interop types that +refer to the same JS interface, you need to rename at least one of them. +Another example is if the JS name can't be written in Dart, such as `$a`. -In order to do this, you can use the [`@JS()`] annotation with a constant -string value. For example: +To do this, you can use the [`@JS()`][] annotation with +a constant string value. +For example: ```dart extension type Array._(JSArray _) implements JSArray { @@ -296,7 +344,7 @@ extension type Array._(JSArray _) implements JSArray { } ``` -Calling either `push` or `pushString` will result in JS code that uses `push`. +Calling either `push` or `pushString` results in JS code that uses `push`. You can also rename interop types: @@ -309,13 +357,14 @@ extension type JSDate._(JSObject _) implements JSObject { } ``` -Calling `JSDate()` will result in a JS invocation of `new Date()`. Similarly, -calling `JSDate.now()` will result in a JS invocation of `Date.now()`. +Calling `JSDate()` results in a JS invocation of `new Date()`. +Similarly, calling `JSDate.now()` results in a JS invocation of `Date.now()`. -Furthermore, you can namespace an entire library, which will add a prefix to all -interop top-level members, interop types, and `static` interop members within -those types. This is useful if you want to avoid adding too many members to the -global JS scope. +Furthermore, you can namespace an entire library, +adding a prefix to all interop top-level members, interop types, +and `static` interop members within those types. +This is useful if you want to avoid adding +too many members to the global JS scope. ```dart @JS('library1') @@ -333,14 +382,15 @@ extension type JSType._(JSObject _) implements JSObject { } ``` -Calling `method()` will result in a JS invocation of `library1.method()`, -calling `JSType()` will result in a JS invocation of `new library1.JSType()`, -and calling `JSType.staticMember` will result in a JS invocation of -`library1.JSType.staticMember`. +Calling `method()` results in a JS invocation of `library1.method()`, +calling `JSType()` results in a JS invocation of `new library1.JSType()`, +and calling `JSType.staticMember` results in +a JS invocation of `library1.JSType.staticMember`. Unlike interop members and interop types, Dart only ever adds a library name in -the JS invocation if you provide a non-empty value in the `@JS()` annotation on -the library. It does not use the Dart name of the library as the default. +the JS invocation if you provide a non-empty value in +the `@JS()` annotation on the library. +It doesn't use the Dart name of the library as the default. ```dart library interop_library; @@ -351,11 +401,11 @@ import 'dart:js_interop'; external void method(); ``` -Calling `method()` will result in a JS invocation of `method()` and not +Calling `method()` results in a JS invocation of `method()` and not `interop_library.method()`. -You can also write multiple namespaces delimited by a `.` for libraries, -top-level members, and interop types: +You can also write multiple namespaces delimited by a `.` for +libraries, top-level members, and interop types: ```dart @JS('library1.library2') @@ -372,34 +422,39 @@ extension type JSType._(JSObject _) implements JSObject { } ``` -Calling `method()` will result in a JS invocation of -`library1.library2.library3.method()`, calling `JSType()` will result in a JS -invocation of `new library1.library2.library3.JSType()`, and so forth. +Calling `method()` results in +a JS invocation of `library1.library2.library3.method()`, +calling `JSType()` results in +a JS invocation of `new library1.library2.library3.JSType()`, and so forth. -You can't use `@JS()` annotations with `.` in the value on interop type members -or extension members of interop types, however. +However, you can't use `@JS()` annotations with `.` in +the value on interop type members or extension members of interop types. -If there is no value provided to `@JS()` or the value is empty, no renaming will -occur. +If there's no value provided to `@JS()` or the value is empty, +no renaming occurs. -`@JS()` also tells the compiler that a member or type is intended to be treated -as a JS interop member or type. It is required (with or without a value) for all -top-level members to distinguish them from other `external` top-level members, -but can often be elided on and within interop types and on extension members as -the compiler can tell it is a JS interop type from the representation type and -on-type. +`@JS()` also tells the compiler that a member or type is +intended to be treated as a JS interop member or type. +It is required (with or without a value) for all top-level members to +distinguish them from other `external` top-level members, but +can often be elided on and within interop types and on extension members as +the compiler can tell it is a JS interop type from +the representation type and on-type. + +[`@JS()`]: {{site.dart-api}}/dart-js_interop/JS-class.html ## Export Dart functions and objects to JS {:#export} -The above sections show how to call JS members from Dart. It's also useful to -*export* Dart code so that it can be used in JS. To export a Dart function to -JS, first convert it using [`Function.toJS`], which wraps the Dart function with -a JS function. Then, pass the wrapped function to JS through an interop member. +The preceding sections show how to call JS members from Dart. +It's also useful to *export* Dart code so that it can be used in JS. +To export a Dart function to JS, first convert it using [`Function.toJS`][], +which wraps the Dart function with a JS function. +Then, pass the wrapped function to JS through an interop member. At that point, it's ready to be called by other JS code. -For example, this code converts a Dart function and uses interop to set it in a -global property, which is then called in JS: +For example, this code converts a Dart function and uses interop to +set it in a global property, which is then called in JS: ```dart import 'dart:js_interop'; @@ -420,73 +475,59 @@ void main() { globalThis.exportedFunction('hello world'); ``` -Functions that are exported this way have type [restrictions] similar to those -of interop members. +Functions that are exported this way have type [restrictions][] similar to +those of interop members. + +Sometimes it's useful to export an entire Dart interface so that +JS can interact with a Dart object. +To do this, mark the Dart class as exportable using [`@JSExport`][] and +wrap instances of that class using [`createJSInteropWrapper`][]. +For a more detailed explanation of this technique, including how to +mock JS values, check out [How to mock JavaScript interop objects][]. -Sometimes it's useful to export an entire Dart interface so that JS can interact -with a Dart object. To do this, mark the Dart class as exportable using -[`@JSExport`] and wrap instances of that class using [`createJSInteropWrapper`]. -For a more detailed explanation of this technique, including how to mock JS -values, see the [mocking tutorial]. +[`Function.toJS`]: {{site.dart-api}}/dart-js_interop/FunctionToJSExportedDartFunction/toJS.html +[restrictions]: /interop/js-interop/js-types#requirements-on-external-declarations-and-function-tojs +[`@JSExport`]: {{site.dart-api}}/dart-js_interop/JSExport-class.html +[`createJSInteropWrapper`]: {{site.dart-api}}/dart-js_interop/createJSInteropWrapper.html +[How to mock JavaScript interop objects]: /interop/js-interop/mock ## `dart:js_interop` and `dart:js_interop_unsafe` -[`dart:js_interop`] contains all the necessary members you should need, +[`dart:js_interop`][] contains all the necessary members you should need, including `@JS`, JS types, conversion functions, and various utility functions. Utility functions include: -- [`globalContext`], which represents the global scope that the compilers use to - find interop members and types. -- [Helpers to inspect the type of JS values] +- [`globalContext`][], which represents the global scope that + the compilers use to find interop members and types. +- [Helpers to inspect the type of JS values][] - JS operators -- [`dartify`] and [`jsify`], which check the type of certain JS values and - convert them to Dart values and vice versa. Prefer using the specific - conversion when you know the type of the JS value, as the extra type-checking - may be expensive. -- [`importModule`], which allows you to import modules dynamically as - `JSObject`s. +- [`dartify`][] and [`jsify`][], which check the type of certain JS values and + convert them to Dart values and vice versa. + Prefer using the specific conversion when you know the type of the JS value, + as the extra type-checking might be expensive. +- [`importModule`][], which allows you to + import modules dynamically as a `JSObject`. -More utilities may be added to this library in the future. +More utilities might be added to this library in the future. -[`dart:js_interop_unsafe`] contains members that allow you to look up properties -dynamically. For example: +[`dart:js_interop_unsafe`][] contains members that allow +you to look up properties dynamically. For example: ```dart JSFunction f = console['log']; ``` -Instead of declaring an interop member named `log`, we're instead using a string -to represent the property. `dart:js_interop_unsafe` provides functionality to -dynamically get, set, and call properties. +Instead of declaring an interop member named `log`, +a string can be used to access the property. +`dart:js_interop_unsafe` also provides functions to +dynamically check for, get, set, and call properties. :::tip -Avoid using `dart:js_interop_unsafe` if possible. It makes security compliance -more difficult to guarantee and may lead to violations, which is why it can be -"unsafe". +Avoid using `dart:js_interop_unsafe` if possible. +It makes security compliance more difficult to guarantee and +might lead to violations, which is why it can be "unsafe". ::: -{% comment %} -TODO: Some of these are not available on stable. How do we link to dev? -{% endcomment %} - -[global JS scope]: https://developer.mozilla.org/docs/Glossary/Global_scope -[conversion functions]: /interop/js-interop/js-types#conversions -[contains a primitive type]: /interop/js-interop/js-types#requirements-on-external-declarations-and-function-tojs -["JS type"]: /interop/js-interop/js-types -[`Window`]: https://developer.mozilla.org/docs/Web/API/Window -[check the type of the JS value through interop]: /interop/js-interop/js-types#compatibility-type-checks-and-casts -[`package:web`]: {{site.pub-pkg}}/web -[`external`]: /language/functions#external -[restrictions]: /interop/js-interop/js-types#requirements-on-external-declarations-and-function-tojs -[object literal]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Object_initializer -[54801]: {{site.repo.dart.sdk}}/issues/54801 -[property accessors]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Property_accessors#bracket_notation -[utility functions]: {{site.dart-api}}/dart-js_interop/JSAnyOperatorExtension.html -[`@JS()`]: {{site.dart-api}}/dart-js_interop/JS-class.html -[`Function.toJS`]: {{site.dart-api}}/dart-js_interop/FunctionToJSExportedDartFunction/toJS.html -[`@JSExport`]: {{site.dart-api}}/dart-js_interop/JSExport-class.html -[`createJSInteropWrapper`]: {{site.dart-api}}/dart-js_interop/createJSInteropWrapper.html -[mocking tutorial]: /interop/js-interop/mock [`dart:js_interop`]: {{site.dart-api}}/dart-js_interop/dart-js_interop-library.html [`globalContext`]: {{site.dart-api}}/dart-js_interop/globalContext.html [Helpers to inspect the type of JS values]: {{site.dart-api}}/dart-js_interop/JSAnyUtilityExtension.html @@ -494,9 +535,3 @@ TODO: Some of these are not available on stable. How do we link to dev? [`jsify`]: {{site.dart-api}}/dart-js_interop/NullableObjectUtilExtension/jsify.html [`importModule`]: {{site.dart-api}}/dart-js_interop/importModule.html [`dart:js_interop_unsafe`]: {{site.dart-api}}/dart-js_interop_unsafe/dart-js_interop_unsafe-library.html -[extensions]: /language/extension-methods -[extension type]: /language/extension-types -[runtime guarantee]: /language/extension-types#type-considerations -[representation type]: /language/extension-types#declaration -[implement]: /language/extension-types#implements -[non-`external` members]: /language/extension-types#members