invalid_ runtime_ check_ with_ js_ interop_ types
Learn about the invalid_runtime_check_with_js_interop_types linter rule.
Avoid runtime type tests with JS interop types where the result may not be platform-consistent.
Details
#
DON'T use is checks where the
type is a JS interop type.
DON'T use is checks where the
type is a generic Dart type that has JS interop type
arguments.
DON'T use is checks with a JS
interop value.
dart:js_interop types have runtime types that are
different based on whether you are compiling to JS or to Wasm.
Therefore, runtime type checks may result in different
behavior. Runtime checks also do not necessarily check that a
JS interop value is a particular JavaScript type.
BAD:
extension type HTMLElement(JSObject o) {}
extension type HTMLDivElement(JSObject o) implements HTMLElement {}
void compute(JSAny a, bool b, List<JSObject> lo, List<String> ls, JSObject o,
HTMLElement e) {
a is String; // LINT, checking that a JS value is a Dart type
b is JSBoolean; // LINT, checking that a Dart value is a JS type
a is JSString; // LINT, checking that a JS value is a different JS interop
// type
o is JSNumber; // LINT, checking that a JS value is a different JS interop
// type
lo is List<String>; // LINT, JS interop type argument and Dart type argument
// are incompatible
ls is List<JSString>; // LINT, Dart type argument and JS interop type argument
// are incompatible
lo is List<JSArray>; // LINT, comparing JS interop type argument with
// different JS interop type argument
lo is List<JSNumber>; // LINT, comparing JS interop type argument with
// different JS interop type argument
o is HTMLElement; // LINT, true because both are JSObjects but doesn't check
// that it's a JS HTMLElement
e is HTMLDivElement; // LINT, true because both are JSObjects but doesn't
// check that it's a JS HTMLDivElement
}
Prefer using JS interop helpers like isA from
dart:js_interop to check the underlying type of
JS interop values.
GOOD:
extension type HTMLElement(JSObject o) implements JSObject {}
extension type HTMLDivElement(JSObject o) implements HTMLElement {}
void compute(JSAny a, List<JSAny> l, JSObject o, HTMLElement e, Object obj) {
a.isA<JSString>; // OK, uses JS interop to check it is a JS string
l[0].isA<JSString>; // OK, uses JS interop to check it is a JS string
o.isA<HTMLElement>(); // OK, uses JS interop to check `o` is an HTMLElement
e.isA<HTMLDivElement>(); // OK, uses JS interop to check `e` is an
// HTMLDivElement
obj.isA<JSObject>(); // OK, uses JS interop to check `obj` is a JSObject
}
DON'T use as to cast a JS
interop value to an unrelated Dart type or an unrelated Dart
value to a JS interop type.
DON'T use as to cast a JS
interop value to a JS interop type represented by an
incompatible dart:js_interop type.
BAD:
extension type Window(JSObject o) {}
void compute(String s, JSBoolean b, Window w, List<String> l,
List<JSObject> lo) {
s as JSString; // LINT, casting Dart type to JS interop type
b as bool; // LINT, casting JS interop type to Dart type
b as JSNumber; // LINT, JSBoolean and JSNumber are incompatible
b as Window; // LINT, JSBoolean and JSObject are incompatible
w as JSBoolean; // LINT, JSObject and JSBoolean are incompatible
l as List<JSString>; // LINT, casting Dart value with Dart type argument to
// Dart type with JS interop type argument
lo as List<String>; // LINT, casting Dart value with JS interop type argument
// to Dart type with Dart type argument
lo as List<JSBoolean>; // LINT, casting Dart value with JS interop type
// argument to Dart type with incompatible JS interop
// type argument
}
Prefer using dart:js_interop conversion methods
to convert a JS interop value to a Dart value and vice versa.
GOOD:
extension type Window(JSObject o) {}
extension type Document(JSObject o) {}
void compute(String s, JSBoolean b, Window w, JSArray<JSString> a,
List<String> ls, JSObject o, List<JSAny> la) {
s.toJS; // OK, converts the Dart type to a JS type
b.toDart; // OK, converts the JS type to a Dart type
a.toDart; // OK, converts the JS type to a Dart type
w as Document; // OK, but no runtime check that `w` is a JS Document
ls.map((e) => e.toJS).toList(); // OK, converts the Dart types to JS types
o as JSArray<JSString>; // OK, JSObject and JSArray are compatible
la as List<JSString>; // OK, JSAny and JSString are compatible
(o as Object) as JSObject; // OK, Object is a supertype of JSAny
}
**DON'T** use a JS interop type in a catch clause. If the code in the try
block is expected to throw a JS value, don't use a type at all in the
catch clause.
**BAD:**
```dart
@JS()
external void throwSomething();
extension type JSError(JSObject _) implements JSObject {}
void compute() {
try {
throwSomething();
} on JSString catch (e) { // LINT, checking that the caught value is a JS type
print('string $e');
} on JSError catch (e) { // LINT, checking that the caught value is a JS
// interop type
print('JSError: $e');
} on List<JSNumber> catch (e) { // LINT, type contains a JS interop type
print('List<JSNumber>: $e');
} on bool catch (e) { // NO LINT, but may be platform-dependent
print('bool: $e');
}
}
Use isA from dart:js_interop to
check if a value is a JS interop type within the catch block.
If the code in the try block is expected to throw a JS value,
leave the catch clause untyped and check for all JS interop
types first using isA before checking for Dart
types.
GOOD:
@JS()
external void throwSomething();
extension type JSError(JSObject _) implements JSObject {}
void compute() {
try {
throwSomething();
} catch (e) {
if (e.isA<JSString>()) { // OK, uses JS interop to check it is a JS string
print('string: $e');
} else if (e.isA<JSError>()) { // OK, uses JS interop to check it is a JSError
print('Error: $e');
} else if (e.isA<JSAny>()) { // OK, checks all interop types before Dart types
print('JSAny: $e');
} else if (e is bool) { // OK, `e` can't be a JS value
print('boolean: $e');
}
}
}
Enable
#
To enable the
invalid_runtime_check_with_js_interop_types rule,
add invalid_runtime_check_with_js_interop_types
under
linter > rules in your
analysis_options.yaml
file:
linter:
rules:
- invalid_runtime_check_with_js_interop_types
If you're instead using the YAML map syntax to configure
linter rules, add
invalid_runtime_check_with_js_interop_types: true
under linter > rules:
linter:
rules:
invalid_runtime_check_with_js_interop_types: true
除非另有说明,文档之所提及适用于 Dart 3.12.2 版本报告页面问题.