Version 2.16.0-100.0.dev

Merge commit '08aeef030324baae1e01da44fb3e5713124edd3c' into 'dev'
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 24937db..e9f6fb0 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -252,7 +252,8 @@
 
     if (_classHasStaticInteropAnnotation &&
         procedure.isInstanceMember &&
-        !procedure.isFactory) {
+        !procedure.isFactory &&
+        !procedure.isSynthetic) {
       _diagnosticsReporter.report(
           templateJsInteropStaticInteropWithInstanceMembers
               .withArguments(procedure.enclosingClass!.name),
diff --git a/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart b/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart
new file mode 100644
index 0000000..e00c88e
--- /dev/null
+++ b/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart
@@ -0,0 +1,183 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/clone.dart';
+import 'package:kernel/core_types.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/src/replacement_visitor.dart';
+import 'package:_js_interop_checks/src/js_interop.dart';
+
+class _TypeSubstitutor extends ReplacementVisitor {
+  final Class _javaScriptObject;
+  _TypeSubstitutor(this._javaScriptObject);
+
+  @override
+  DartType? visitInterfaceType(InterfaceType type, int variance) {
+    if (hasStaticInteropAnnotation(type.classNode)) {
+      return InterfaceType(_javaScriptObject, type.declaredNullability);
+    }
+    return super.visitInterfaceType(type, variance);
+  }
+}
+
+/// Erases usage of `@JS` classes that are annotated with `@staticInterop` in
+/// favor of `JavaScriptObject`.
+class StaticInteropClassEraser extends Transformer {
+  final Class _javaScriptObject;
+  final CloneVisitorNotMembers _cloner = CloneVisitorNotMembers();
+  late final _TypeSubstitutor _typeSubstitutor;
+
+  StaticInteropClassEraser(CoreTypes coreTypes)
+      : _javaScriptObject =
+            coreTypes.index.getClass('dart:_interceptors', 'JavaScriptObject') {
+    _typeSubstitutor = _TypeSubstitutor(_javaScriptObject);
+  }
+
+  String _factoryStubName(Procedure factoryTarget) =>
+      '${factoryTarget.name}|staticInteropFactoryStub';
+
+  /// Either finds or creates a static method stub to replace factories with a
+  /// body in a static interop class.
+  ///
+  /// Modifies [factoryTarget]'s enclosing class to include the new method.
+  Procedure _findOrCreateFactoryStub(Procedure factoryTarget) {
+    assert(factoryTarget.isFactory);
+    var factoryClass = factoryTarget.enclosingClass!;
+    assert(hasStaticInteropAnnotation(factoryClass));
+    var stubName = _factoryStubName(factoryTarget);
+    var stubs = factoryClass.procedures
+        .where((procedure) => procedure.name.text == stubName);
+    if (stubs.isEmpty) {
+      // Note that the return type of the cloned function is transformed.
+      var functionNode =
+          super.visitFunctionNode(_cloner.clone(factoryTarget.function))
+              as FunctionNode;
+      var staticMethod = Procedure(
+          Name(stubName), ProcedureKind.Method, functionNode,
+          isStatic: true, fileUri: factoryTarget.fileUri)
+        ..parent = factoryClass;
+      factoryClass.procedures.add(staticMethod);
+      return staticMethod;
+    } else {
+      assert(stubs.length == 1);
+      return stubs.first;
+    }
+  }
+
+  @override
+  TreeNode visitConstructor(Constructor node) {
+    if (hasStaticInteropAnnotation(node.enclosingClass)) {
+      // Transform children of the constructor node excluding the return type.
+      var returnType = node.function.returnType;
+      var newConstructor = super.visitConstructor(node) as Constructor;
+      newConstructor.function.returnType = returnType;
+      return newConstructor;
+    }
+    return super.visitConstructor(node);
+  }
+
+  @override
+  TreeNode visitProcedure(Procedure node) {
+    // Avoid changing the return types of factories, but rather cast the type of
+    // the invocation.
+    if (node.isFactory && hasStaticInteropAnnotation(node.enclosingClass!)) {
+      if (node.function.body != null && !node.isRedirectingFactory) {
+        // Bodies of factories may undergo transformation, which may result in
+        // type invariants breaking. For a motivating example, consider:
+        //
+        // ```
+        // factory Foo.fact() => Foo.cons();
+        // ```
+        //
+        // The invocation of `cons` would have its type erased, but then it
+        // would no longer match the return type of `fact`, whose return type
+        // shouldn't get erased as it is a factory. Note that this is only an
+        // issue when the factory has a body that doesn't simply redirect.
+        //
+        // In order to circumvent this, we introduce a new static method that
+        // clones the factory body and has a return type of
+        // `JavaScriptObject`. Invocations of the factory are turned into
+        // invocations of the static method. The original factory is still kept
+        // in order to make modular compilations work.
+        _findOrCreateFactoryStub(node);
+        return node;
+      } else {
+        // Transform children of the factory node excluding the return type and
+        // return type of the signature type.
+        var returnType = node.function.returnType;
+        var signatureReturnType = node.signatureType?.returnType;
+        var newProcedure = super.visitProcedure(node) as Procedure;
+        newProcedure.function.returnType = returnType;
+        var signatureType = newProcedure.signatureType;
+        if (signatureType != null && signatureReturnType != null) {
+          newProcedure.signatureType = FunctionType(
+              signatureType.positionalParameters,
+              signatureReturnType,
+              signatureType.declaredNullability,
+              namedParameters: signatureType.namedParameters,
+              typeParameters: signatureType.typeParameters,
+              requiredParameterCount: signatureType.requiredParameterCount,
+              typedefType: signatureType.typedefType);
+        }
+        return newProcedure;
+      }
+    }
+    return super.visitProcedure(node);
+  }
+
+  @override
+  TreeNode visitConstructorInvocation(ConstructorInvocation node) {
+    if (hasStaticInteropAnnotation(node.target.enclosingClass)) {
+      // Add a cast so that the result gets typed as `JavaScriptObject`.
+      var newInvocation = super.visitConstructorInvocation(node) as Expression;
+      return AsExpression(
+          newInvocation,
+          InterfaceType(_javaScriptObject,
+              node.target.function.returnType.declaredNullability))
+        ..fileOffset = newInvocation.fileOffset;
+    }
+    return super.visitConstructorInvocation(node);
+  }
+
+  /// Transform static invocations that correspond only to factories of static
+  /// interop classes.
+  @override
+  TreeNode visitStaticInvocation(StaticInvocation node) {
+    var targetClass = node.target.enclosingClass;
+    if (node.target.isFactory &&
+        targetClass != null &&
+        hasStaticInteropAnnotation(targetClass)) {
+      var factoryTarget = node.target;
+      if (factoryTarget.function.body != null &&
+          !factoryTarget.isRedirectingFactory) {
+        // Use or create the static method that replaces this factory instead.
+        // Note that the static method will not have been created yet in the
+        // case where we visit the factory later. Also note that a cast is not
+        // needed since the static method already has its type erased.
+        var args = super.visitArguments(node.arguments) as Arguments;
+        return StaticInvocation(_findOrCreateFactoryStub(factoryTarget), args,
+            isConst: node.isConst)
+          ..fileOffset = node.fileOffset;
+      } else {
+        // Add a cast so that the result gets typed as `JavaScriptObject`.
+        var newInvocation = super.visitStaticInvocation(node) as Expression;
+        return AsExpression(
+            newInvocation,
+            InterfaceType(_javaScriptObject,
+                node.target.function.returnType.declaredNullability))
+          ..fileOffset = newInvocation.fileOffset;
+      }
+    }
+    return super.visitStaticInvocation(node);
+  }
+
+  @override
+  DartType visitDartType(DartType type) {
+    // Variance is not a factor in our type transformation here, so just choose
+    // `unrelated` as a default.
+    var substitutedType = type.accept1(_typeSubstitutor, Variance.unrelated);
+    return substitutedType != null ? substitutedType : type;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart b/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
index be632dc..b143cd4 100644
--- a/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
+++ b/pkg/analysis_server/lib/src/utilities/extensions/range_factory.dart
@@ -67,11 +67,15 @@
     }
   }
 
-  /// Return a source range that covers the given [node] from the start of
-  /// any leading comment token (excluding any token considered a trailing
-  /// comment for the previous node) or the start of the node itself if there
-  /// are none, up until the end of the trailing comment token or the end of the
-  /// node itself if there are none.
+  /// Return a source range that covers the given [node] with any leading and
+  /// trailing comments.
+  ///
+  /// The range begins at the start of any leading comment token (excluding any
+  /// token considered a trailing comment for the previous node) or the start
+  /// of the node itself if there are none.
+  ///
+  /// The range ends at the end of the trailing comment token or the end of the
+  /// node itself if there is not one.
   SourceRange nodeWithComments(LineInfo lineInfo, AstNode node) {
     // If the node is the first thing in the unit, leading comments are treated
     // as headers and should never be included in the range.
diff --git a/pkg/analysis_server/test/src/utilities/extensions/range_factory_test.dart b/pkg/analysis_server/test/src/utilities/extensions/range_factory_test.dart
index 259d5ea..e8d35e3 100644
--- a/pkg/analysis_server/test/src/utilities/extensions/range_factory_test.dart
+++ b/pkg/analysis_server/test/src/utilities/extensions/range_factory_test.dart
@@ -70,8 +70,8 @@
         ? testCode.indexOf(endsBefore)
         : testCode.indexOf(endsAfter!) + endsAfter.length;
 
-    assert(offset > -1);
-    assert(end > -1);
+    expect(offset, greaterThanOrEqualTo(0));
+    expect(end, greaterThanOrEqualTo(0));
 
     return SourceRange(offset, end - offset);
   }
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 6e7d50d..d9e553e 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -38,7 +38,6 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
 
 /// Two or more string literals that are implicitly concatenated because of
@@ -318,7 +317,9 @@
 
   /// Return either this node or the most immediate ancestor of this node for
   /// which the [predicate] returns `true`, or `null` if there is no such node.
-  E? thisOrAncestorMatching<E extends AstNode>(Predicate<AstNode> predicate);
+  E? thisOrAncestorMatching<E extends AstNode>(
+    bool Function(AstNode) predicate,
+  );
 
   /// Return either this node or the most immediate ancestor of this node that
   /// has the given type, or `null` if there is no such node.
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index b78a8e8..d9e8915 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/src/dart/ast/to_source_visitor.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/fasta/token_utils.dart' as util show findPrevious;
-import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
@@ -784,7 +783,9 @@
   }
 
   @override
-  E? thisOrAncestorMatching<E extends AstNode>(Predicate<AstNode> predicate) {
+  E? thisOrAncestorMatching<E extends AstNode>(
+    bool Function(AstNode) predicate,
+  ) {
     AstNode? node = this;
     while (node != null && !predicate(node)) {
       node = node.parent;
@@ -9336,12 +9337,11 @@
   Token literal;
 
   /// The value of the literal.
-  String _value;
+  @override
+  String value;
 
   /// Initialize a newly created simple string literal.
-  SimpleStringLiteralImpl(this.literal, this._value) {
-    _value = StringUtilities.intern(value);
-  }
+  SimpleStringLiteralImpl(this.literal, this.value);
 
   @override
   Token get beginToken => literal;
@@ -9370,13 +9370,6 @@
   @override
   bool get isSynthetic => literal.isSynthetic;
 
-  @override
-  String get value => _value;
-
-  set value(String string) {
-    _value = StringUtilities.intern(_value);
-  }
-
   StringLexemeHelper get _helper {
     return StringLexemeHelper(literal.lexeme, true, true);
   }
@@ -9579,12 +9572,12 @@
       if (isRaw) {
         start++;
       }
-      if (StringUtilities.startsWith3(lexeme, start, 0x27, 0x27, 0x27)) {
+      if (lexeme.startsWith("'''", start)) {
         isSingleQuoted = true;
         isMultiline = true;
         start += 3;
         start = _trimInitialWhitespace(start);
-      } else if (StringUtilities.startsWith3(lexeme, start, 0x22, 0x22, 0x22)) {
+      } else if (lexeme.startsWith('"""', start)) {
         isSingleQuoted = false;
         isMultiline = true;
         start += 3;
@@ -9602,12 +9595,10 @@
     end = lexeme.length;
     if (isLast) {
       if (start + 3 <= end &&
-          (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) ||
-              StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27))) {
+          (lexeme.endsWith("'''") || lexeme.endsWith('"""'))) {
         end -= 3;
       } else if (start + 1 <= end &&
-          (StringUtilities.endsWithChar(lexeme, 0x22) ||
-              StringUtilities.endsWithChar(lexeme, 0x27))) {
+          (lexeme.endsWith("'") || lexeme.endsWith('"'))) {
         end -= 1;
       }
     }
diff --git a/pkg/analyzer/lib/src/generated/java_engine.dart b/pkg/analyzer/lib/src/generated/java_engine.dart
index 82c2f23..e880604 100644
--- a/pkg/analyzer/lib/src/generated/java_engine.dart
+++ b/pkg/analyzer/lib/src/generated/java_engine.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/generated/interner.dart';
-import 'package:analyzer/src/generated/java_core.dart';
 
 export 'package:analyzer/exception/exception.dart';
 
@@ -41,115 +40,12 @@
     return lineStarts;
   }
 
-  static bool endsWith3(String str, int c1, int c2, int c3) {
-    var length = str.length;
-    return length >= 3 &&
-        str.codeUnitAt(length - 3) == c1 &&
-        str.codeUnitAt(length - 2) == c2 &&
-        str.codeUnitAt(length - 1) == c3;
-  }
-
   static bool endsWithChar(String str, int c) {
     int length = str.length;
     return length > 0 && str.codeUnitAt(length - 1) == c;
   }
 
-  static int indexOf1(String str, int start, int c) {
-    int index = start;
-    int last = str.length;
-    while (index < last) {
-      if (str.codeUnitAt(index) == c) {
-        return index;
-      }
-      index++;
-    }
-    return -1;
-  }
-
-  static int indexOf2(String str, int start, int c1, int c2) {
-    int index = start;
-    int last = str.length - 1;
-    while (index < last) {
-      if (str.codeUnitAt(index) == c1 && str.codeUnitAt(index + 1) == c2) {
-        return index;
-      }
-      index++;
-    }
-    return -1;
-  }
-
-  static int indexOf4(
-      String string, int start, int c1, int c2, int c3, int c4) {
-    int index = start;
-    int last = string.length - 3;
-    while (index < last) {
-      if (string.codeUnitAt(index) == c1 &&
-          string.codeUnitAt(index + 1) == c2 &&
-          string.codeUnitAt(index + 2) == c3 &&
-          string.codeUnitAt(index + 3) == c4) {
-        return index;
-      }
-      index++;
-    }
-    return -1;
-  }
-
-  static int indexOf5(
-      String str, int start, int c1, int c2, int c3, int c4, int c5) {
-    int index = start;
-    int last = str.length - 4;
-    while (index < last) {
-      if (str.codeUnitAt(index) == c1 &&
-          str.codeUnitAt(index + 1) == c2 &&
-          str.codeUnitAt(index + 2) == c3 &&
-          str.codeUnitAt(index + 3) == c4 &&
-          str.codeUnitAt(index + 4) == c5) {
-        return index;
-      }
-      index++;
-    }
-    return -1;
-  }
-
-  /// Return the index of the first not letter/digit character in the [string]
-  /// that is at or after the [startIndex]. Return the length of the [string] if
-  /// all characters to the end are letters/digits.
-  static int indexOfFirstNotLetterDigit(String string, int startIndex) {
-    int index = startIndex;
-    int last = string.length;
-    while (index < last) {
-      int c = string.codeUnitAt(index);
-      if (!Character.isLetterOrDigit(c)) {
-        return index;
-      }
-      index++;
-    }
-    return last;
-  }
-
   static String intern(String string) => INTERNER.intern(string);
-  static bool isEmpty(String? s) {
-    return s == null || s.isEmpty;
-  }
-
-  static bool isTagName(String? s) {
-    if (s == null || s.isEmpty) {
-      return false;
-    }
-    int sz = s.length;
-    for (int i = 0; i < sz; i++) {
-      int c = s.codeUnitAt(i);
-      if (!Character.isLetter(c)) {
-        if (i == 0) {
-          return false;
-        }
-        if (!Character.isDigit(c) && c != 0x2D) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
 
   /// Produce a string containing all of the names in the given array,
   /// surrounded by single quotes, and separated by commas.
@@ -180,85 +76,4 @@
     buffer.write("'");
     return buffer.toString();
   }
-
-  static bool startsWith2(String str, int start, int c1, int c2) {
-    return str.length - start >= 2 &&
-        str.codeUnitAt(start) == c1 &&
-        str.codeUnitAt(start + 1) == c2;
-  }
-
-  static bool startsWith3(String str, int start, int c1, int c2, int c3) {
-    return str.length - start >= 3 &&
-        str.codeUnitAt(start) == c1 &&
-        str.codeUnitAt(start + 1) == c2 &&
-        str.codeUnitAt(start + 2) == c3;
-  }
-
-  static bool startsWith4(
-      String str, int start, int c1, int c2, int c3, int c4) {
-    return str.length - start >= 4 &&
-        str.codeUnitAt(start) == c1 &&
-        str.codeUnitAt(start + 1) == c2 &&
-        str.codeUnitAt(start + 2) == c3 &&
-        str.codeUnitAt(start + 3) == c4;
-  }
-
-  static bool startsWith5(
-      String str, int start, int c1, int c2, int c3, int c4, int c5) {
-    return str.length - start >= 5 &&
-        str.codeUnitAt(start) == c1 &&
-        str.codeUnitAt(start + 1) == c2 &&
-        str.codeUnitAt(start + 2) == c3 &&
-        str.codeUnitAt(start + 3) == c4 &&
-        str.codeUnitAt(start + 4) == c5;
-  }
-
-  static bool startsWith6(
-      String str, int start, int c1, int c2, int c3, int c4, int c5, int c6) {
-    return str.length - start >= 6 &&
-        str.codeUnitAt(start) == c1 &&
-        str.codeUnitAt(start + 1) == c2 &&
-        str.codeUnitAt(start + 2) == c3 &&
-        str.codeUnitAt(start + 3) == c4 &&
-        str.codeUnitAt(start + 4) == c5 &&
-        str.codeUnitAt(start + 5) == c6;
-  }
-
-  static String? substringBefore(String? str, String? separator) {
-    if (str == null || str.isEmpty) {
-      return str;
-    }
-    if (separator == null) {
-      return str;
-    }
-    int pos = str.indexOf(separator);
-    if (pos < 0) {
-      return str;
-    }
-    return str.substring(0, pos);
-  }
-
-  static String substringBeforeChar(String str, int c) {
-    if (isEmpty(str)) {
-      return str;
-    }
-    int pos = indexOf1(str, 0, c);
-    if (pos < 0) {
-      return str;
-    }
-    return str.substring(0, pos);
-  }
-}
-
-class UUID {
-  static const int __nextId = 0;
-
-  final String id;
-
-  UUID(this.id);
-
-  @override
-  String toString() => id;
-
-  static UUID randomUUID() => UUID((__nextId).toString());
 }
diff --git a/pkg/analyzer/test/generated/utilities_test.dart b/pkg/analyzer/test/generated/utilities_test.dart
index a95e1f4..42f04ed 100644
--- a/pkg/analyzer/test/generated/utilities_test.dart
+++ b/pkg/analyzer/test/generated/utilities_test.dart
@@ -2587,92 +2587,12 @@
     expect(StringUtilities.EMPTY_ARRAY.length, 0);
   }
 
-  void test_endsWith3() {
-    expect(StringUtilities.endsWith3("abc", 0x61, 0x62, 0x63), isTrue);
-    expect(StringUtilities.endsWith3("abcdefghi", 0x67, 0x68, 0x69), isTrue);
-    expect(StringUtilities.endsWith3("abcdefghi", 0x64, 0x65, 0x61), isFalse);
-    // missing
-  }
-
   void test_endsWithChar() {
     expect(StringUtilities.endsWithChar("a", 0x61), isTrue);
     expect(StringUtilities.endsWithChar("b", 0x61), isFalse);
     expect(StringUtilities.endsWithChar("", 0x61), isFalse);
   }
 
-  void test_indexOf1() {
-    expect(StringUtilities.indexOf1("a", 0, 0x61), 0);
-    expect(StringUtilities.indexOf1("abcdef", 0, 0x61), 0);
-    expect(StringUtilities.indexOf1("abcdef", 0, 0x63), 2);
-    expect(StringUtilities.indexOf1("abcdef", 0, 0x66), 5);
-    expect(StringUtilities.indexOf1("abcdef", 0, 0x7A), -1);
-    expect(StringUtilities.indexOf1("abcdef", 1, 0x61), -1);
-    // before start
-  }
-
-  void test_indexOf2() {
-    expect(StringUtilities.indexOf2("ab", 0, 0x61, 0x62), 0);
-    expect(StringUtilities.indexOf2("abcdef", 0, 0x61, 0x62), 0);
-    expect(StringUtilities.indexOf2("abcdef", 0, 0x63, 0x64), 2);
-    expect(StringUtilities.indexOf2("abcdef", 0, 0x65, 0x66), 4);
-    expect(StringUtilities.indexOf2("abcdef", 0, 0x64, 0x61), -1);
-    expect(StringUtilities.indexOf2("abcdef", 1, 0x61, 0x62), -1);
-    // before start
-  }
-
-  void test_indexOf4() {
-    expect(StringUtilities.indexOf4("abcd", 0, 0x61, 0x62, 0x63, 0x64), 0);
-    expect(StringUtilities.indexOf4("abcdefghi", 0, 0x61, 0x62, 0x63, 0x64), 0);
-    expect(StringUtilities.indexOf4("abcdefghi", 0, 0x63, 0x64, 0x65, 0x66), 2);
-    expect(StringUtilities.indexOf4("abcdefghi", 0, 0x66, 0x67, 0x68, 0x69), 5);
-    expect(
-        StringUtilities.indexOf4("abcdefghi", 0, 0x64, 0x65, 0x61, 0x64), -1);
-    expect(
-        StringUtilities.indexOf4("abcdefghi", 1, 0x61, 0x62, 0x63, 0x64), -1);
-    // before start
-  }
-
-  void test_indexOf5() {
-    expect(
-        StringUtilities.indexOf5("abcde", 0, 0x61, 0x62, 0x63, 0x64, 0x65), 0);
-    expect(
-        StringUtilities.indexOf5("abcdefghi", 0, 0x61, 0x62, 0x63, 0x64, 0x65),
-        0);
-    expect(
-        StringUtilities.indexOf5("abcdefghi", 0, 0x63, 0x64, 0x65, 0x66, 0x67),
-        2);
-    expect(
-        StringUtilities.indexOf5("abcdefghi", 0, 0x65, 0x66, 0x67, 0x68, 0x69),
-        4);
-    expect(
-        StringUtilities.indexOf5("abcdefghi", 0, 0x64, 0x65, 0x66, 0x69, 0x6E),
-        -1);
-    expect(
-        StringUtilities.indexOf5("abcdefghi", 1, 0x61, 0x62, 0x63, 0x64, 0x65),
-        -1);
-    // before start
-  }
-
-  void test_isEmpty() {
-    expect(StringUtilities.isEmpty(""), isTrue);
-    expect(StringUtilities.isEmpty(" "), isFalse);
-    expect(StringUtilities.isEmpty("a"), isFalse);
-    expect(StringUtilities.isEmpty(StringUtilities.EMPTY), isTrue);
-  }
-
-  void test_isTagName() {
-    expect(StringUtilities.isTagName(null), isFalse);
-    expect(StringUtilities.isTagName(""), isFalse);
-    expect(StringUtilities.isTagName("-"), isFalse);
-    expect(StringUtilities.isTagName("0"), isFalse);
-    expect(StringUtilities.isTagName("0a"), isFalse);
-    expect(StringUtilities.isTagName("a b"), isFalse);
-    expect(StringUtilities.isTagName("a0"), isTrue);
-    expect(StringUtilities.isTagName("a"), isTrue);
-    expect(StringUtilities.isTagName("ab"), isTrue);
-    expect(StringUtilities.isTagName("a-b"), isTrue);
-  }
-
   void test_printListOfQuotedNames_empty() {
     expect(() {
       StringUtilities.printListOfQuotedNames([]);
@@ -2707,107 +2627,4 @@
     expect(StringUtilities.printListOfQuotedNames(<String>["a", "b"]),
         "'a' and 'b'");
   }
-
-  void test_startsWith2() {
-    expect(StringUtilities.startsWith2("ab", 0, 0x61, 0x62), isTrue);
-    expect(StringUtilities.startsWith2("abcdefghi", 0, 0x61, 0x62), isTrue);
-    expect(StringUtilities.startsWith2("abcdefghi", 2, 0x63, 0x64), isTrue);
-    expect(StringUtilities.startsWith2("abcdefghi", 5, 0x66, 0x67), isTrue);
-    expect(StringUtilities.startsWith2("abcdefghi", 0, 0x64, 0x64), isFalse);
-    // missing
-  }
-
-  void test_startsWith3() {
-    expect(StringUtilities.startsWith3("abc", 0, 0x61, 0x62, 0x63), isTrue);
-    expect(
-        StringUtilities.startsWith3("abcdefghi", 0, 0x61, 0x62, 0x63), isTrue);
-    expect(
-        StringUtilities.startsWith3("abcdefghi", 2, 0x63, 0x64, 0x65), isTrue);
-    expect(
-        StringUtilities.startsWith3("abcdefghi", 6, 0x67, 0x68, 0x69), isTrue);
-    expect(
-        StringUtilities.startsWith3("abcdefghi", 0, 0x64, 0x65, 0x61), isFalse);
-    // missing
-  }
-
-  void test_startsWith4() {
-    expect(
-        StringUtilities.startsWith4("abcd", 0, 0x61, 0x62, 0x63, 0x64), isTrue);
-    expect(StringUtilities.startsWith4("abcdefghi", 0, 0x61, 0x62, 0x63, 0x64),
-        isTrue);
-    expect(StringUtilities.startsWith4("abcdefghi", 2, 0x63, 0x64, 0x65, 0x66),
-        isTrue);
-    expect(StringUtilities.startsWith4("abcdefghi", 5, 0x66, 0x67, 0x68, 0x69),
-        isTrue);
-    expect(StringUtilities.startsWith4("abcdefghi", 0, 0x64, 0x65, 0x61, 0x64),
-        isFalse);
-    // missing
-  }
-
-  void test_startsWith5() {
-    expect(
-        StringUtilities.startsWith5("abcde", 0, 0x61, 0x62, 0x63, 0x64, 0x65),
-        isTrue);
-    expect(
-        StringUtilities.startsWith5(
-            "abcdefghi", 0, 0x61, 0x62, 0x63, 0x64, 0x65),
-        isTrue);
-    expect(
-        StringUtilities.startsWith5(
-            "abcdefghi", 2, 0x63, 0x64, 0x65, 0x66, 0x67),
-        isTrue);
-    expect(
-        StringUtilities.startsWith5(
-            "abcdefghi", 4, 0x65, 0x66, 0x67, 0x68, 0x69),
-        isTrue);
-    expect(
-        StringUtilities.startsWith5(
-            "abcdefghi", 0, 0x61, 0x62, 0x63, 0x62, 0x61),
-        isFalse);
-    // missing
-  }
-
-  void test_startsWith6() {
-    expect(
-        StringUtilities.startsWith6(
-            "abcdef", 0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66),
-        isTrue);
-    expect(
-        StringUtilities.startsWith6(
-            "abcdefghi", 0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66),
-        isTrue);
-    expect(
-        StringUtilities.startsWith6(
-            "abcdefghi", 2, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68),
-        isTrue);
-    expect(
-        StringUtilities.startsWith6(
-            "abcdefghi", 3, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69),
-        isTrue);
-    expect(
-        StringUtilities.startsWith6(
-            "abcdefghi", 0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67),
-        isFalse);
-    // missing
-  }
-
-  void test_substringBefore() {
-    expect(StringUtilities.substringBefore(null, ""), null);
-    expect(StringUtilities.substringBefore(null, "a"), null);
-    expect(StringUtilities.substringBefore("", "a"), "");
-    expect(StringUtilities.substringBefore("abc", "a"), "");
-    expect(StringUtilities.substringBefore("abcba", "b"), "a");
-    expect(StringUtilities.substringBefore("abc", "c"), "ab");
-    expect(StringUtilities.substringBefore("abc", "d"), "abc");
-    expect(StringUtilities.substringBefore("abc", ""), "");
-    expect(StringUtilities.substringBefore("abc", null), "abc");
-  }
-
-  void test_substringBeforeChar() {
-    expect(StringUtilities.substringBeforeChar("", 0x61), "");
-    expect(StringUtilities.substringBeforeChar("abc", 0x61), "");
-    expect(StringUtilities.substringBeforeChar("abcba", 0x62), "a");
-    expect(StringUtilities.substringBeforeChar("abc", 0x63), "ab");
-    expect(StringUtilities.substringBeforeChar("abc", 0x64), "abc");
-  }
 }
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index d4e63fb..cead301 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -302,6 +302,8 @@
 
   InterfaceType get jsJavaScriptFunctionType;
 
+  ClassEntity get jsLegacyJavaScriptObjectClass;
+
   ClassEntity get jsJavaScriptObjectClass;
 
   ClassEntity get jsIndexableClass;
@@ -1348,6 +1350,12 @@
   InterfaceType get jsJavaScriptFunctionType =>
       _getRawType(jsJavaScriptFunctionClass);
 
+  ClassEntity _jsLegacyJavaScriptObjectClass;
+  @override
+  ClassEntity get jsLegacyJavaScriptObjectClass =>
+      _jsLegacyJavaScriptObjectClass ??=
+          _findInterceptorsClass('LegacyJavaScriptObject');
+
   ClassEntity _jsJavaScriptObjectClass;
   @override
   ClassEntity get jsJavaScriptObjectClass =>
@@ -2166,7 +2174,7 @@
   ClassEntity getDefaultSuperclass(
       ClassEntity cls, NativeBasicData nativeBasicData) {
     if (nativeBasicData.isJsInteropClass(cls)) {
-      return jsJavaScriptObjectClass;
+      return jsLegacyJavaScriptObjectClass;
     }
     // Native classes inherit from Interceptor.
     return nativeBasicData.isNativeClass(cls)
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index f82c523..170924c 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -520,6 +520,7 @@
         ],
         instantiatedClasses: [
           _commonElements.jsJavaScriptObjectClass,
+          _commonElements.jsLegacyJavaScriptObjectClass,
           _commonElements.jsPlainJavaScriptObjectClass,
           _commonElements.jsJavaScriptFunctionClass
         ],
@@ -607,6 +608,7 @@
     ], globalClasses: [
       _commonElements.jsInterceptorClass,
       _commonElements.jsJavaScriptObjectClass,
+      _commonElements.jsLegacyJavaScriptObjectClass,
       _commonElements.jsPlainJavaScriptObjectClass,
       _commonElements.jsJavaScriptFunctionClass
     ]);
diff --git a/pkg/compiler/lib/src/js_backend/codegen_listener.dart b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
index fe62f76..4a93bce 100644
--- a/pkg/compiler/lib/src/js_backend/codegen_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
@@ -291,6 +291,8 @@
       registerInstantiation(_commonElements.jsNumberClass);
     } else if (cls == _commonElements.jsJavaScriptObjectClass) {
       registerInstantiation(_commonElements.jsJavaScriptObjectClass);
+    } else if (cls == _commonElements.jsLegacyJavaScriptObjectClass) {
+      registerInstantiation(_commonElements.jsLegacyJavaScriptObjectClass);
     } else if (cls == _commonElements.jsPlainJavaScriptObjectClass) {
       registerInstantiation(_commonElements.jsPlainJavaScriptObjectClass);
     } else if (cls == _commonElements.jsUnknownJavaScriptObjectClass) {
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index 02fc83a..0b220af 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -394,6 +394,9 @@
       _addInterceptors(_commonElements.jsNumberClass, impactBuilder);
     } else if (cls == _commonElements.jsJavaScriptObjectClass) {
       _addInterceptors(_commonElements.jsJavaScriptObjectClass, impactBuilder);
+    } else if (cls == _commonElements.jsLegacyJavaScriptObjectClass) {
+      _addInterceptors(
+          _commonElements.jsLegacyJavaScriptObjectClass, impactBuilder);
     } else if (cls == _commonElements.jsPlainJavaScriptObjectClass) {
       _addInterceptors(
           _commonElements.jsPlainJavaScriptObjectClass, impactBuilder);
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index c9130bd..69dc9f4 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -164,7 +164,7 @@
   Set<Class> _unneededNativeClasses;
 
   ClassEntity get _jsInteropInterceptor =>
-      _commonElements.jsJavaScriptObjectClass;
+      _commonElements.jsLegacyJavaScriptObjectClass;
   final List<StubMethod> _jsInteropIsChecks = [];
   final Set<TypeCheck> _jsInteropTypeChecks = {};
 
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index cd26c6b..5e67e37 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -1942,7 +1942,8 @@
   js.Block emitTypeRules(Fragment fragment) {
     List<js.Statement> statements = [];
 
-    ClassEntity jsObjectClass = _commonElements.jsJavaScriptObjectClass;
+    ClassEntity legacyJsObjectClass =
+        _commonElements.jsLegacyJavaScriptObjectClass;
 
     Map<ClassTypeData, List<ClassTypeData>> nativeRedirections =
         _nativeEmitter.typeRedirections;
@@ -1960,10 +1961,11 @@
         erasedTypes[element] = targetType.typeArguments.length;
       }
 
-      bool isInterop = _classHierarchy.isSubclassOf(element, jsObjectClass);
+      bool isInterop =
+          _classHierarchy.isSubclassOf(element, legacyJsObjectClass);
 
-      if (isInterop && element != jsObjectClass) {
-        ruleset.addRedirection(element, jsObjectClass);
+      if (isInterop && element != legacyJsObjectClass) {
+        ruleset.addRedirection(element, legacyJsObjectClass);
       } else {
         Iterable<TypeCheck> checks = typeData.classChecks?.checks ?? const [];
         Iterable<InterfaceType> supertypes = isInterop
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index d379248..17fd5d2 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -246,7 +246,7 @@
   ClassEntity getLubOfInstantiatedSubclasses(ClassEntity cls) {
     if (nativeData.isJsInteropClass(cls)) {
       return getLubOfInstantiatedSubclasses(
-          commonElements.jsJavaScriptObjectClass);
+          commonElements.jsLegacyJavaScriptObjectClass);
     }
     ClassHierarchyNode hierarchy = classHierarchy.getClassHierarchyNode(cls);
     return hierarchy?.getLubOfInstantiatedSubclasses();
@@ -256,7 +256,7 @@
   ClassEntity getLubOfInstantiatedSubtypes(ClassEntity cls) {
     if (nativeData.isJsInteropClass(cls)) {
       return getLubOfInstantiatedSubtypes(
-          commonElements.jsJavaScriptObjectClass);
+          commonElements.jsLegacyJavaScriptObjectClass);
     }
     ClassSet classSet = classHierarchy.getClassSet(cls);
     return classSet?.getLubOfInstantiatedSubtypes();
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index d8985b7..01f42be 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -12,6 +12,7 @@
     show Message, LocatedMessage;
 import 'package:_js_interop_checks/js_interop_checks.dart';
 import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart';
+import 'package:_js_interop_checks/src/transformations/static_interop_class_eraser.dart';
 import 'package:kernel/ast.dart' as ir;
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
@@ -142,6 +143,7 @@
       ChangedStructureNotifier? changedStructureNotifier}) {
     var nativeClasses = JsInteropChecks.getNativeClasses(component);
     var jsUtilOptimizer = JsUtilOptimizer(coreTypes, hierarchy);
+    var staticInteropClassEraser = StaticInteropClassEraser(coreTypes);
     for (var library in libraries) {
       JsInteropChecks(
               coreTypes,
@@ -151,6 +153,7 @@
       // TODO (rileyporter): Merge js_util optimizations with other lowerings
       // in the single pass in `transformations/lowering.dart`.
       jsUtilOptimizer.visitLibrary(library);
+      staticInteropClassEraser.visitLibrary(library);
     }
     lowering.transformLibraries(libraries, coreTypes, hierarchy, options);
     logger?.call("Lowering transformations performed");
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 827bf20..f82c5ef 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -468,7 +468,7 @@
     }
 
     /// This path is needed for synthetically injected superclasses like
-    /// `Interceptor` and `JavaScriptObject`.
+    /// `Interceptor` and `LegacyJavaScriptObject`.
     KClassEnv env = classes.getEnv(superClass);
     ConstructorEntity constructor = env.lookupConstructor(this, target.name);
     if (constructor != null) {
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index e81dda1..f59b9fd 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -820,7 +820,7 @@
         // JS interop API returns dynamic.  This means that to some degree we
         // still use the return type to decide whether to include native types,
         // even though we don't trust the type annotation.
-        ClassEntity cls = commonElements.jsJavaScriptObjectClass;
+        ClassEntity cls = commonElements.jsLegacyJavaScriptObjectClass;
         _behavior.typesInstantiated.add(elementEnvironment.getThisType(cls));
       }
     }
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 2177dd4..26ff0d0 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -115,7 +115,7 @@
         } else if (_dartTypes.isSubtype(
             type,
             _elementEnvironment
-                .getRawType(_commonElements.jsJavaScriptObjectClass))) {
+                .getRawType(_commonElements.jsLegacyJavaScriptObjectClass))) {
           matchingClasses.add(type.element);
         }
         // TODO(johnniwinther): Improve spec string precision to handle type
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 56683e5..73c10d4 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -5083,7 +5083,7 @@
     // resulting code bloat (e.g. from `dart:html`), we unsoundly assume that
     // only JS interop types are returned.
     nativeBehavior.typesInstantiated.add(_elementEnvironment
-        .getThisType(_commonElements.jsJavaScriptObjectClass));
+        .getThisType(_commonElements.jsLegacyJavaScriptObjectClass));
 
     AbstractValue instructionType =
         _typeInferenceMap.typeFromNativeBehavior(nativeBehavior, closedWorld);
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index ea42f4a..9352fa8 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -174,7 +174,7 @@
     if (nativeBasicData.isJsInteropClass(cls)) {
       // We can not tell js-interop classes apart, so we just assume the
       // receiver could be any js-interop class.
-      cls = commonElements.jsJavaScriptObjectClass;
+      cls = commonElements.jsLegacyJavaScriptObjectClass;
       relation = ClassRelation.subtype;
     }
     return StrongModeConstraint.internal(cls, relation);
diff --git a/pkg/compiler/test/impact/data/jsinterop.dart b/pkg/compiler/test/impact/data/jsinterop.dart
index b39e444..0451381 100644
--- a/pkg/compiler/test/impact/data/jsinterop.dart
+++ b/pkg/compiler/test/impact/data/jsinterop.dart
@@ -27,7 +27,7 @@
 
 @JS()
 class JsInteropClass {
-  /*member: JsInteropClass.:static=[JavaScriptObject.(0)]*/
+  /*member: JsInteropClass.:static=[LegacyJavaScriptObject.(0)]*/
   external JsInteropClass();
 
   /*member: JsInteropClass.method:
@@ -50,14 +50,14 @@
 }
 
 /*member: testJsInteropClass:
- dynamic=[JavaScriptObject.method(0)],
+ dynamic=[LegacyJavaScriptObject.method(0)],
  static=[JsInteropClass.(0)]
 */
 testJsInteropClass() => new JsInteropClass().method();
 
 typedef void Callback<T>(T value);
 
-/*member: GenericClass.:static=[JavaScriptObject.(0)]*/
+/*member: GenericClass.:static=[LegacyJavaScriptObject.(0)]*/
 @JS()
 class GenericClass<T> {
   /*member: GenericClass.method:
@@ -113,7 +113,7 @@
 }
 
 /*member: testOptionalGenericFunctionTypeArgument:
- dynamic=[JavaScriptObject.method(0)],
+ dynamic=[LegacyJavaScriptObject.method(0)],
  static=[GenericClass.(0)]
 */
 testOptionalGenericFunctionTypeArgument() => new GenericClass().method();
diff --git a/pkg/compiler/test/inference/data/js_interop.dart b/pkg/compiler/test/inference/data/js_interop.dart
index 994a675..d436c62 100644
--- a/pkg/compiler/test/inference/data/js_interop.dart
+++ b/pkg/compiler/test/inference/data/js_interop.dart
@@ -23,7 +23,7 @@
       {/*[exact=JSUInt31]*/ a, /*Value([exact=JSString], value: "")*/ b});
 }
 
-/*member: anonymousClass:[null|subclass=JavaScriptObject]*/
+/*member: anonymousClass:[null|subclass=LegacyJavaScriptObject]*/
 anonymousClass() => new Class1(a: 1, b: '');
 
 @JS()
@@ -43,9 +43,9 @@
 /*member: jsInteropClass:[subclass=JSInt]*/
 jsInteropClass() {
   JsInteropClass cls = new JsInteropClass();
-  return cls. /*update: [null|subclass=JavaScriptObject]*/ setter =
-      cls. /*[null|subclass=JavaScriptObject]*/ getter /*invoke: [null|subclass=JSInt]*/ +
-          cls. /*invoke: [subclass=JavaScriptObject]*/ method(
+  return cls. /*update: [null|subclass=LegacyJavaScriptObject]*/ setter =
+      cls. /*[null|subclass=LegacyJavaScriptObject]*/ getter /*invoke: [null|subclass=JSInt]*/ +
+          cls. /*invoke: [subclass=LegacyJavaScriptObject]*/ method(
               0) /*invoke: [subclass=JSInt]*/ +
           10;
 }
diff --git a/pkg/compiler/test/jsinterop/internal_annotations_test.dart b/pkg/compiler/test/jsinterop/internal_annotations_test.dart
index efea232..4299a38 100644
--- a/pkg/compiler/test/jsinterop/internal_annotations_test.dart
+++ b/pkg/compiler/test/jsinterop/internal_annotations_test.dart
@@ -106,6 +106,8 @@
         registerClass(world.commonElements.jsInterceptorClass);
     ClassEntity JavaScriptObject =
         registerClass(world.commonElements.jsJavaScriptObjectClass);
+    ClassEntity LegacyJavaScriptObject =
+        registerClass(world.commonElements.jsLegacyJavaScriptObjectClass);
     ClassEntity A = registerClass(findClass(world, 'A'));
     ClassEntity B = registerClass(findClass(world, 'B'));
     ClassEntity C = registerClass(findClass(world, 'C'));
@@ -118,11 +120,13 @@
     Expect.equals(elementEnvironment.getSuperClass(Interceptor), Object_);
     Expect.equals(
         elementEnvironment.getSuperClass(JavaScriptObject), Interceptor);
+    Expect.equals(elementEnvironment.getSuperClass(LegacyJavaScriptObject),
+        JavaScriptObject);
 
-    Expect.equals(elementEnvironment.getSuperClass(A), JavaScriptObject);
-    Expect.equals(elementEnvironment.getSuperClass(B), JavaScriptObject);
-    Expect.equals(elementEnvironment.getSuperClass(C), JavaScriptObject);
-    Expect.equals(elementEnvironment.getSuperClass(D), JavaScriptObject);
+    Expect.equals(elementEnvironment.getSuperClass(A), LegacyJavaScriptObject);
+    Expect.equals(elementEnvironment.getSuperClass(B), LegacyJavaScriptObject);
+    Expect.equals(elementEnvironment.getSuperClass(C), LegacyJavaScriptObject);
+    Expect.equals(elementEnvironment.getSuperClass(D), LegacyJavaScriptObject);
     Expect.equals(elementEnvironment.getSuperClass(E), Object_);
     Expect.equals(elementEnvironment.getSuperClass(F), Object_);
 
@@ -191,28 +195,69 @@
 
   await test('main() {}');
 
-  await test('main() => newA();',
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => newA();', abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 
-  await test('main() => newB();',
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => newB();', abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 
-  await test('main() => newC();',
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => newC();', abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 
-  await test('main() => newD();',
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => newD();', abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 
   await test('main() => newE();', directlyInstantiated: ['E']);
 
   await test('main() => newF();', directlyInstantiated: ['F']);
 
-  await test('main() => [newD(), newE()];',
-      directlyInstantiated: ['E'],
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => [newD(), newE()];', directlyInstantiated: [
+    'E'
+  ], abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 }
diff --git a/pkg/compiler/test/jsinterop/world_test.dart b/pkg/compiler/test/jsinterop/world_test.dart
index bc495ac..6c3253f 100644
--- a/pkg/compiler/test/jsinterop/world_test.dart
+++ b/pkg/compiler/test/jsinterop/world_test.dart
@@ -100,6 +100,8 @@
         registerClass(world.commonElements.jsInterceptorClass);
     ClassEntity JavaScriptObject =
         registerClass(world.commonElements.jsJavaScriptObjectClass);
+    ClassEntity LegacyJavaScriptObject =
+        registerClass(world.commonElements.jsLegacyJavaScriptObjectClass);
     ClassEntity A = registerClass(findClass(world, 'A'));
     ClassEntity B = registerClass(findClass(world, 'B'));
     ClassEntity C = registerClass(findClass(world, 'C'));
@@ -112,11 +114,13 @@
     Expect.equals(elementEnvironment.getSuperClass(Interceptor), Object_);
     Expect.equals(
         elementEnvironment.getSuperClass(JavaScriptObject), Interceptor);
+    Expect.equals(elementEnvironment.getSuperClass(LegacyJavaScriptObject),
+        JavaScriptObject);
 
-    Expect.equals(elementEnvironment.getSuperClass(A), JavaScriptObject);
-    Expect.equals(elementEnvironment.getSuperClass(B), JavaScriptObject);
-    Expect.equals(elementEnvironment.getSuperClass(C), JavaScriptObject);
-    Expect.equals(elementEnvironment.getSuperClass(D), JavaScriptObject);
+    Expect.equals(elementEnvironment.getSuperClass(A), LegacyJavaScriptObject);
+    Expect.equals(elementEnvironment.getSuperClass(B), LegacyJavaScriptObject);
+    Expect.equals(elementEnvironment.getSuperClass(C), LegacyJavaScriptObject);
+    Expect.equals(elementEnvironment.getSuperClass(D), LegacyJavaScriptObject);
     Expect.equals(elementEnvironment.getSuperClass(E), Object_);
     Expect.equals(elementEnvironment.getSuperClass(F), Object_);
 
@@ -185,28 +189,69 @@
 
   await test('main() {}');
 
-  await test('main() => newA();',
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => newA();', abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 
-  await test('main() => newB();',
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => newB();', abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 
-  await test('main() => newC();',
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => newC();', abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 
-  await test('main() => newD();',
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => newD();', abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 
   await test('main() => newE();', directlyInstantiated: ['E']);
 
   await test('main() => newF();', directlyInstantiated: ['F']);
 
-  await test('main() => [newD(), newE()];',
-      directlyInstantiated: ['E'],
-      abstractlyInstantiated: ['A', 'B', 'C', 'D'],
-      indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+  await test('main() => [newD(), newE()];', directlyInstantiated: [
+    'E'
+  ], abstractlyInstantiated: [
+    'A',
+    'B',
+    'C',
+    'D'
+  ], indirectlyInstantiated: [
+    'Object',
+    'Interceptor',
+    'JavaScriptObject',
+    'LegacyJavaScriptObject'
+  ]);
 }
diff --git a/pkg/compiler/test/rti/emission/jsinterop.dart b/pkg/compiler/test/rti/emission/jsinterop.dart
index f88db92..0e06b73 100644
--- a/pkg/compiler/test/rti/emission/jsinterop.dart
+++ b/pkg/compiler/test/rti/emission/jsinterop.dart
@@ -7,7 +7,7 @@
 @JS()
 library jsinterop;
 
-/*class: global#JavaScriptObject:checks=[$isA,$isC],instance*/
+/*class: global#LegacyJavaScriptObject:checks=[$isA,$isC],instance*/
 
 import 'package:js/js.dart';
 
diff --git a/pkg/compiler/test/rti/emission/jsinterop_generic.dart b/pkg/compiler/test/rti/emission/jsinterop_generic.dart
index d409967..31cade2 100644
--- a/pkg/compiler/test/rti/emission/jsinterop_generic.dart
+++ b/pkg/compiler/test/rti/emission/jsinterop_generic.dart
@@ -11,7 +11,7 @@
 
 // TODO(johnniwinther): Avoid generating duplicate is/as function when multiple
 // jsinterop classes implement the same interface.
-/*class: global#JavaScriptObject:checks=[$isA,$isB,$isB],instance*/
+/*class: global#LegacyJavaScriptObject:checks=[$isA,$isB,$isB],instance*/
 
 import 'package:expect/expect.dart';
 import 'package:js/js.dart';
diff --git a/pkg/compiler/test/rti/emission/jsinterop_generic_factory_args.dart b/pkg/compiler/test/rti/emission/jsinterop_generic_factory_args.dart
index 897ffea..77b181d 100644
--- a/pkg/compiler/test/rti/emission/jsinterop_generic_factory_args.dart
+++ b/pkg/compiler/test/rti/emission/jsinterop_generic_factory_args.dart
@@ -7,7 +7,7 @@
 @JS()
 library foo;
 
-/*class: global#JavaScriptObject:*/
+/*class: global#LegacyJavaScriptObject:*/
 
 import 'package:expect/expect.dart';
 import 'package:js/js.dart';
diff --git a/pkg/dart2js_info/test/hello_world_deferred/hello_world_deferred.js.info.json b/pkg/dart2js_info/test/hello_world_deferred/hello_world_deferred.js.info.json
index 490a537..8e31503 100644
--- a/pkg/dart2js_info/test/hello_world_deferred/hello_world_deferred.js.info.json
+++ b/pkg/dart2js_info/test/hello_world_deferred/hello_world_deferred.js.info.json
@@ -2012,7 +2012,7 @@
       "851867060": {
         "id": "class/851867060",
         "kind": "class",
-        "name": "JavaScriptObject",
+        "name": "LegacyJavaScriptObject",
         "size": 225,
         "outputUnit": "outputUnit/669725655",
         "parent": "library/325218131",
diff --git a/pkg/dev_compiler/lib/src/kernel/module_symbols.dart b/pkg/dev_compiler/lib/src/kernel/module_symbols.dart
index 73f14cf..6b9f782 100644
--- a/pkg/dev_compiler/lib/src/kernel/module_symbols.dart
+++ b/pkg/dev_compiler/lib/src/kernel/module_symbols.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 // Dart debug symbol information stored by DDC.
 //
 // The data format below stores descriptions of dart code objects and their
@@ -90,94 +88,113 @@
   static const SemanticVersion current = SemanticVersion(0, 0, 1);
 
   /// Semantic version of the format.
-  String version;
+  final String version;
 
   /// Module name as used in the module metadata
-  String moduleName;
+  final String moduleName;
 
   /// All dart libraries included in the module.
   ///
   /// Note here and below that imported elements are not included in
   /// the current module but can be referenced by their ids.
-  List<LibrarySymbol> libraries;
+  final List<LibrarySymbol> libraries;
 
   /// All dart scripts included in the module.
-  List<Script> scripts;
+  final List<Script> scripts;
 
   /// All dart classes included in the module.
-  List<ClassSymbol> classes;
+  final List<ClassSymbol> classes;
 
   /// All dart function types included in the module.
-  List<FunctionTypeSymbol> functionTypes;
+  final List<FunctionTypeSymbol> functionTypes;
 
   /// All dart function types included in the module.
-  List<FunctionSymbol> functions;
+  final List<FunctionSymbol> functions;
 
   /// All dart scopes included in the module.
   ///
   /// Does not include scopes listed in other fields,
   /// such as libraries, classes, and functions.
-  List<ScopeSymbol> scopes;
+  final List<ScopeSymbol> scopes;
 
-  /// All dart variables included in the module.
+  /// All Dart variables included in the module.
   List<VariableSymbol> variables;
+
   ModuleSymbols({
-    this.version,
-    this.moduleName,
-    this.libraries,
-    this.scripts,
-    this.classes,
-    this.functionTypes,
-    this.functions,
-    this.scopes,
-    this.variables,
-  });
-  ModuleSymbols.fromJson(Map<String, dynamic> json) {
-    version = _createValue(json['version'], ifNull: current.version);
+    String? version,
+    required this.moduleName,
+    List<LibrarySymbol>? libraries,
+    List<Script>? scripts,
+    List<ClassSymbol>? classes,
+    List<FunctionTypeSymbol>? functionTypes,
+    List<FunctionSymbol>? functions,
+    List<ScopeSymbol>? scopes,
+    List<VariableSymbol>? variables,
+  })  : version = version ??= current.version,
+        libraries = libraries ?? [],
+        scripts = scripts ?? [],
+        classes = classes ?? [],
+        functionTypes = functionTypes ?? [],
+        functions = functions ?? [],
+        scopes = scopes ?? [],
+        variables = variables ?? [];
+
+  ModuleSymbols.fromJson(Map<String, dynamic> json)
+      : version = _readAndValidateVersionFromJson(json['version']),
+        moduleName = _createValue(json['moduleName']),
+        libraries = _createObjectList(
+            json['libraries'], (json) => LibrarySymbol.fromJson(json)),
+        scripts =
+            _createObjectList(json['scripts'], (json) => Script.fromJson(json)),
+        classes = _createObjectList(
+            json['classes'], (json) => ClassSymbol.fromJson(json)),
+        functionTypes = _createObjectList(
+            json['functionTypes'], (json) => FunctionTypeSymbol.fromJson(json)),
+        functions = _createObjectList(
+            json['functions'], (json) => FunctionSymbol.fromJson(json)),
+        scopes = _createObjectList(
+            json['scopes'], (json) => ScopeSymbol.fromJson(json)),
+        variables = _createObjectList(
+            json['variables'], (json) => VariableSymbol.fromJson(json));
+
+  @override
+  Map<String, dynamic> toJson() {
+    final json = <String, dynamic>{
+      'version': version,
+      'moduleName': moduleName,
+    };
+    _setObjectListIfNotNullOrEmpty(json, 'libraries', libraries);
+    _setObjectListIfNotNullOrEmpty(json, 'scripts', scripts);
+    _setObjectListIfNotNullOrEmpty(json, 'classes', classes);
+    _setObjectListIfNotNullOrEmpty(json, 'functionTypes', functionTypes);
+    _setObjectListIfNotNullOrEmpty(json, 'functions', functions);
+    _setObjectListIfNotNullOrEmpty(json, 'scopes', scopes);
+    _setObjectListIfNotNullOrEmpty(json, 'variables', variables);
+    return json;
+  }
+
+  static String _readAndValidateVersionFromJson(dynamic json) {
+    if (json == null) return current.version;
+    var version = _createValue<String>(json);
     if (!current.isCompatibleWith(version)) {
       throw Exception('Unsupported version $version. '
           'Current version: ${current.version}');
     }
-    moduleName = _createValue(json['moduleName']);
-    libraries = _createObjectList(
-        json['libraries'], (json) => LibrarySymbol.fromJson(json));
-    scripts =
-        _createObjectList(json['scripts'], (json) => Script.fromJson(json));
-    classes = _createObjectList(
-        json['classes'], (json) => ClassSymbol.fromJson(json));
-    functionTypes = _createObjectList(
-        json['functionTypes'], (json) => FunctionTypeSymbol.fromJson(json));
-    functions = _createObjectList(
-        json['functions'], (json) => FunctionSymbol.fromJson(json));
-    scopes =
-        _createObjectList(json['scopes'], (json) => ScopeSymbol.fromJson(json));
-    variables = _createObjectList(
-        json['variables'], (json) => VariableSymbol.fromJson(json));
-  }
-  @override
-  Map<String, dynamic> toJson() {
-    final json = <String, dynamic>{};
-    _setValueIfNotNull(json, 'version', version);
-    _setValueIfNotNull(json, 'moduleName', moduleName);
-    _setObjectListIfNotNull(json, 'libraries', libraries);
-    _setObjectListIfNotNull(json, 'scripts', scripts);
-    _setObjectListIfNotNull(json, 'classes', classes);
-    _setObjectListIfNotNull(json, 'functionTypes', functionTypes);
-    _setObjectListIfNotNull(json, 'functions', functions);
-    _setObjectListIfNotNull(json, 'scopes', scopes);
-    _setObjectListIfNotNull(json, 'variables', variables);
-    return json;
+    return version;
   }
 }
 
 class Symbol implements SymbolTableElement {
   /// Local id (such as JS name) for the symbol.
   ///
-  /// Used to map from dart objects to JS objects inside a scope.
-  String localId;
+  /// Used to map from Dart objects to JS objects inside a scope.
+  final String localId;
 
   /// Enclosing scope of the symbol.
-  String scopeId;
+  final String? scopeId;
+
+  /// Source location of the symbol.
+  final SourceLocation? location;
 
   /// Unique Id, shared with JS representation (if any).
   ///
@@ -186,20 +203,20 @@
   /// Where scope refers to a Library, Class, Function, or Scope.
   String get id => scopeId == null ? localId : '$scopeId|$localId';
 
-  /// Source location of the symbol.
-  SourceLocation location;
-  Symbol({this.localId, this.scopeId, this.location});
-  Symbol.fromJson(Map<String, dynamic> json) {
-    localId = _createValue(json['localId']);
-    scopeId = _createValue(json['scopeId']);
-    location = _createObject(
-        json['location'], (json) => SourceLocation.fromJson(json));
-  }
+  Symbol({required this.localId, this.scopeId, this.location});
+
+  Symbol.fromJson(Map<String, dynamic> json)
+      : localId = _createValue(json['localId']),
+        scopeId = _createValue(json['scopeId']),
+        location = _createNullableObject(
+            json['location'], (json) => SourceLocation.fromJson(json));
+
   @override
   Map<String, dynamic> toJson() {
-    final json = <String, dynamic>{};
-    _setValueIfNotNull(json, 'localId', localId);
-    _setValueIfNotNull(json, 'scopeId', scopeId);
+    final json = <String, dynamic>{
+      'localId': localId,
+      if (scopeId != null) 'scopeId': scopeId,
+    };
     _setObjectIfNotNull(json, 'location', location);
     return json;
   }
@@ -210,6 +227,7 @@
 }
 
 enum VariableSymbolKind { global, local, property, field, formal, none }
+
 VariableSymbolKind parseVariableSymbolKind(String value) {
   return VariableSymbolKind.values.singleWhere((e) => value == '$e',
       orElse: () {
@@ -218,189 +236,210 @@
 }
 
 class VariableSymbol extends Symbol {
-  /// Variable name
-  String name;
+  /// Name of the variable in Dart source code.
+  final String name;
 
   /// Symbol kind.
-  VariableSymbolKind kind;
+  final VariableSymbolKind kind;
 
-  /// The declared type of this symbol.
-  String typeId;
+  /// The declared type of this symbol in Dart source code.
+  // TODO(nshahan) Only nullable until we design how to identify types from
+  // other modules.
+  final String? typeId;
 
-  /// Is this variable const?
-  bool isConst;
+  /// True if this variable const.
+  final bool isConst;
 
-  /// Is this variable final?
-  bool isFinal;
+  /// True if this variable final.
+  final bool isFinal;
 
-  /// Is this variable static?
-  bool isStatic;
+  /// True if this variable static.
+  final bool isStatic;
 
   /// Property getter, if any.
-  String getterId;
+  final String? getterId;
 
   /// Property setter, if any.
-  String setterId;
+  final String? setterId;
+
   VariableSymbol({
-    this.name,
-    this.kind,
-    this.isConst,
-    this.isFinal,
-    this.isStatic,
-    this.typeId,
-    String localId,
-    String scopeId,
-    SourceLocation location,
-  }) : super(localId: localId, scopeId: scopeId, location: location);
-  VariableSymbol.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
-    name = _createValue(json['name']);
-    kind = _createValue(json['kind'],
-        parse: parseVariableSymbolKind, ifNull: VariableSymbolKind.none);
-    isConst = _createValue(json['isConst']);
-    isFinal = _createValue(json['isFinal']);
-    isStatic = _createValue(json['isStatic']);
-    typeId = _createValue(json['typeId']);
-    setterId = _createValue(json['setterId']);
-    getterId = _createValue(json['getterId']);
-  }
+    required this.name,
+    required this.kind,
+    required this.typeId,
+    bool? isConst,
+    bool? isFinal,
+    bool? isStatic,
+    this.getterId,
+    this.setterId,
+    required String localId,
+    required String scopeId,
+    required SourceLocation location,
+  })  : isConst = isConst ?? false,
+        isFinal = isFinal ?? false,
+        isStatic = isStatic ?? false,
+        super(localId: localId, scopeId: scopeId, location: location);
+
+  VariableSymbol.fromJson(Map<String, dynamic> json)
+      : name = _createValue(json['name']),
+        kind = _createValue(json['kind'],
+            parse: parseVariableSymbolKind, ifNull: VariableSymbolKind.none),
+        typeId = _createValue(json['typeId']),
+        isConst = _createValue(json['isConst']),
+        isFinal = _createValue(json['isFinal']),
+        isStatic = _createValue(json['isStatic']),
+        getterId = _createValue(json['getterId']),
+        setterId = _createValue(json['setterId']),
+        super.fromJson(json);
+
   @override
-  Map<String, dynamic> toJson() {
-    final json = super.toJson();
-    _setValueIfNotNull(json, 'name', name);
-    _setValueIfNotNull(json, 'kind', kind.toString());
-    _setValueIfNotNull(json, 'isConst', isConst);
-    _setValueIfNotNull(json, 'isFinal', isFinal);
-    _setValueIfNotNull(json, 'isStatic', isStatic);
-    _setValueIfNotNull(json, 'typeId', typeId);
-    _setValueIfNotNull(json, 'setterId', setterId);
-    _setValueIfNotNull(json, 'getterId', getterId);
-    return json;
-  }
+  Map<String, dynamic> toJson() => {
+        ...super.toJson(),
+        'name': name,
+        'kind': kind.toString(),
+        if (typeId != null) 'typeId': typeId,
+        'isConst': isConst,
+        'isFinal': isFinal,
+        'isStatic': isStatic,
+        if (getterId != null) 'getterId': getterId,
+        if (setterId != null) 'setterId': setterId,
+      };
 }
 
 class ClassSymbol extends ScopeSymbol implements TypeSymbol {
-  /// The name of this class.
-  String name;
+  /// The name of this class in Dart source code.
+  final String name;
 
-  /// Is this an abstract class?
-  bool isAbstract;
+  /// True if this class is abstract.
+  final bool isAbstract;
 
-  /// Is this a const class?
-  bool isConst;
+  /// True if this class is const.
+  final bool isConst;
 
   /// The superclass of this class, if any.
-  String superClassId;
+  final String? superClassId;
 
   /// A list of interface types for this class.
-  List<String> interfaceIds;
+  final List<String> interfaceIds;
 
-  /// Mapping of type parameter dart names to JS names.
-  Map<String, String> typeParameters;
+  /// Mapping of type parameter Dart names to JS names.
+  final Map<String, String> typeParameters;
 
   /// Library that contains this class.
-  String get libraryId => scopeId;
+  String get libraryId => scopeId!;
 
   /// Fields in this class.
   ///
   /// Including static fields, methods, and properties.
   List<String> get fieldIds => variableIds;
 
-  /// A list of functions in this class.
+  /// Functions in this class.
   ///
   /// Includes all static functions, methods, getters,
   /// and setters in the current class.
   ///
   /// Does not include functions from superclasses.
   List<String> get functionIds => scopeIds;
+
   ClassSymbol({
-    this.name,
-    this.isAbstract,
-    this.isConst,
+    required this.name,
+    bool? isAbstract,
+    bool? isConst,
     this.superClassId,
-    this.interfaceIds,
-    this.typeParameters,
-    String localId,
-    String scopeId,
-    SourceLocation location,
-    List<String> variableIds,
-    List<String> scopeIds,
-  }) : super(
+    List<String>? interfaceIds,
+    Map<String, String>? typeParameters,
+    required String localId,
+    required String scopeId,
+    required SourceLocation location,
+    List<String>? variableIds,
+    List<String>? scopeIds,
+  })  : isAbstract = isAbstract ?? false,
+        isConst = isConst ?? false,
+        interfaceIds = interfaceIds ?? [],
+        typeParameters = typeParameters ?? {},
+        super(
             localId: localId,
             scopeId: scopeId,
             variableIds: variableIds,
             scopeIds: scopeIds,
             location: location);
-  ClassSymbol.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
-    name = _createValue(json['name']);
-    isAbstract = _createValue(json['isAbstract']);
-    isConst = _createValue(json['isConst']);
-    superClassId = _createValue(json['superClassId']);
-    interfaceIds = _createValueList(json['interfaceIds']);
-    typeParameters = _createValueMap(json['typeParameters']);
-  }
+
+  ClassSymbol.fromJson(Map<String, dynamic> json)
+      : name = _createValue(json['name']),
+        isAbstract = _createValue(json['isAbstract']),
+        isConst = _createValue(json['isConst']),
+        superClassId = _createValue(json['superClassId']),
+        interfaceIds = _createValueList(json['interfaceIds']),
+        typeParameters = _createValueMap(json['typeParameters']),
+        super.fromJson(json);
+
   @override
-  Map<String, dynamic> toJson() {
-    final json = super.toJson();
-    _setValueIfNotNull(json, 'name', name);
-    _setValueIfNotNull(json, 'isAbstract', isAbstract);
-    _setValueIfNotNull(json, 'isConst', isConst);
-    _setValueIfNotNull(json, 'superClassId', superClassId);
-    _setValueIfNotNull(json, 'interfaceIds', interfaceIds);
-    _setValueIfNotNull(json, 'typeParameters', typeParameters);
-    return json;
-  }
+  Map<String, dynamic> toJson() => {
+        ...super.toJson(),
+        'name': name,
+        'isAbstract': isAbstract,
+        'isConst': isConst,
+        if (superClassId != null) 'superClassId': superClassId,
+        if (interfaceIds.isNotEmpty) 'interfaceIds': interfaceIds,
+        if (typeParameters.isNotEmpty) 'typeParameters': typeParameters,
+      };
 }
 
 class FunctionTypeSymbol extends Symbol implements TypeSymbol {
   /// Mapping of dart type parameter names to JS names.
-  Map<String, String> typeParameters;
+  final Map<String, String> typeParameters;
 
   /// Types for positional parameters for this function.
-  List<String> parameterTypeIds;
+  final List<String> parameterTypeIds;
 
   /// Types for optional positional parameters for this function.
-  List<String> optionalParameterTypeIds;
+  final List<String> optionalParameterTypeIds;
 
   /// Names and types for named parameters for this function.
-  Map<String, String> namedParameterTypeIds;
+  final Map<String, String> namedParameterTypeIds;
 
-  /// A return type for this function.
-  String returnTypeId;
+  /// The return type for this function.
+  final String returnTypeId;
+
   FunctionTypeSymbol({
-    this.typeParameters,
-    this.parameterTypeIds,
-    this.optionalParameterTypeIds,
-    this.namedParameterTypeIds,
-    this.returnTypeId,
-    String localId,
-    String scopeId,
-    SourceLocation location,
-  }) : super(localId: localId, scopeId: scopeId, location: location);
+    Map<String, String>? typeParameters,
+    List<String>? parameterTypeIds,
+    List<String>? optionalParameterTypeIds,
+    Map<String, String>? namedParameterTypeIds,
+    required this.returnTypeId,
+    required String localId,
+    required String scopeId,
+    required SourceLocation location,
+  })  : typeParameters = typeParameters ?? {},
+        parameterTypeIds = parameterTypeIds ?? [],
+        optionalParameterTypeIds = optionalParameterTypeIds ?? [],
+        namedParameterTypeIds = namedParameterTypeIds ?? {},
+        super(localId: localId, scopeId: scopeId, location: location);
+
   FunctionTypeSymbol.fromJson(Map<String, dynamic> json)
-      : super.fromJson(json) {
-    parameterTypeIds = _createValueList(json['parameterTypeIds']);
-    optionalParameterTypeIds =
-        _createValueList(json['optionalParameterTypeIds']);
-    typeParameters = _createValueMap(json['typeParameters']);
-    namedParameterTypeIds = _createValueMap(json['namedParameterTypeIds']);
-    returnTypeId = _createValue(json['returnTypeId']);
-  }
+      : parameterTypeIds = _createValueList(json['parameterTypeIds']),
+        optionalParameterTypeIds =
+            _createValueList(json['optionalParameterTypeIds']),
+        typeParameters = _createValueMap(json['typeParameters']),
+        namedParameterTypeIds = _createValueMap(json['namedParameterTypeIds']),
+        returnTypeId = _createValue(json['returnTypeId']),
+        super.fromJson(json);
+
   @override
-  Map<String, dynamic> toJson() {
-    final json = super.toJson();
-    _setValueIfNotNull(json, 'typeParameters', typeParameters);
-    _setValueIfNotNull(json, 'parameterTypeIds', parameterTypeIds);
-    _setValueIfNotNull(
-        json, 'optionalParameterTypeIds', optionalParameterTypeIds);
-    _setValueIfNotNull(json, 'namedParameterTypeIds', namedParameterTypeIds);
-    _setValueIfNotNull(json, 'returnTypeId', returnTypeId);
-    return json;
-  }
+  Map<String, dynamic> toJson() => {
+        ...super.toJson(),
+        if (typeParameters.isNotEmpty) 'typeParameters': typeParameters,
+        if (parameterTypeIds.isNotEmpty) 'parameterTypeIds': parameterTypeIds,
+        if (optionalParameterTypeIds.isNotEmpty)
+          'optionalParameterTypeIds': optionalParameterTypeIds,
+        if (namedParameterTypeIds.isNotEmpty)
+          'namedParameterTypeIds': namedParameterTypeIds,
+        'returnTypeId': returnTypeId,
+      };
 }
 
 class FunctionSymbol extends ScopeSymbol {
   /// The name of this function.
-  String name;
+  final String name;
 
   /// Unique Id, shared with JS representation (if any).
   ///
@@ -410,232 +449,238 @@
   /// Where scope refers to a Library, Class, Function, or Scope.
   /// String id;
   /// Declared type of this function.
-  String typeId;
+  // TODO(nshahan) Only nullable because unused at this time.
+  final String? typeId;
 
-  /// Is this function static?
-  bool isStatic;
+  /// True if this function is static.
+  final bool isStatic;
 
-  /// Is this function const?
-  bool isConst;
+  /// True if this function is const.
+  final bool isConst;
+
   FunctionSymbol({
-    this.name,
-    this.typeId,
-    this.isStatic,
-    this.isConst,
-    String localId,
-    String scopeId,
-    List<String> variableIds,
-    List<String> scopeIds,
-    SourceLocation location,
-  }) : super(
+    required this.name,
+    required this.typeId,
+    bool? isStatic,
+    bool? isConst,
+    required String localId,
+    required String scopeId,
+    List<String>? variableIds,
+    List<String>? scopeIds,
+    required SourceLocation location,
+  })  : isStatic = isStatic ?? false,
+        isConst = isConst ?? false,
+        super(
           localId: localId,
           scopeId: scopeId,
           variableIds: variableIds,
           scopeIds: scopeIds,
           location: location,
         );
-  FunctionSymbol.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
-    name = _createValue(json['name']);
-    typeId = _createValue(json['typeId']);
-    isStatic = _createValue(json['isStatic']);
-    isConst = _createValue(json['isConst']);
-  }
+
+  FunctionSymbol.fromJson(Map<String, dynamic> json)
+      : name = _createValue(json['name']),
+        typeId = _createValue(json['typeId']),
+        isStatic = _createValue(json['isStatic']),
+        isConst = _createValue(json['isConst']),
+        super.fromJson(json);
+
   @override
-  Map<String, dynamic> toJson() {
-    final json = super.toJson();
-    _setValueIfNotNull(json, 'name', name);
-    _setValueIfNotNull(json, 'typeId', typeId);
-    _setValueIfNotNull(json, 'isStatic', isStatic);
-    _setValueIfNotNull(json, 'isConst', isConst);
-    return json;
-  }
+  Map<String, dynamic> toJson() => {
+        ...super.toJson(),
+        'name': name,
+        if (typeId != null) 'typeId': typeId,
+        'isStatic': isStatic,
+        'isConst': isConst,
+      };
 }
 
 class LibrarySymbol extends ScopeSymbol {
   /// The name of this library.
-  String name;
+  final String name;
 
-  /// Unique Id.
-  ///
-  /// Currently the debugger can find the library uri from JS location
-  /// using source maps and module metadata.
-  ///
-  /// Can be same as library uri.
-  /// String id;
   /// The uri of this library.
-  String uri;
+  final String uri;
 
   /// A list of the imports for this library.
-  List<LibrarySymbolDependency> dependencies;
+  final List<LibrarySymbolDependency> dependencies;
 
   /// A list of the scripts which constitute this library.
-  List<String> scriptIds;
+  final List<String> scriptIds;
+
   LibrarySymbol({
-    this.name,
-    this.uri,
-    this.dependencies,
-    this.scriptIds,
-    List<String> variableIds,
-    List<String> scopeIds,
-  }) : super(
+    String? name,
+    required this.uri,
+    List<LibrarySymbolDependency>? dependencies,
+    required this.scriptIds,
+    List<String>? variableIds,
+    List<String>? scopeIds,
+  })  : name = name ?? '',
+        dependencies = dependencies ?? [],
+        super(
           localId: uri,
           variableIds: variableIds,
           scopeIds: scopeIds,
         );
 
-  LibrarySymbol.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
-    name = _createValue(json['name'], ifNull: '');
-    uri = _createValue(json['uri']);
-    scriptIds = _createValueList(json['scriptIds']);
-    dependencies = _createObjectList(
-        json['dependencies'], (json) => LibrarySymbolDependency.fromJson(json));
-  }
+  LibrarySymbol.fromJson(Map<String, dynamic> json)
+      : name = _createValue(json['name'], ifNull: ''),
+        uri = _createValue(json['uri']),
+        scriptIds = _createValueList(json['scriptIds']),
+        dependencies = _createObjectList(json['dependencies'],
+            (json) => LibrarySymbolDependency.fromJson(json)),
+        super.fromJson(json);
+
   @override
   Map<String, dynamic> toJson() {
-    final json = super.toJson();
-    _setValueIfNotNull(json, 'name', name);
-    _setValueIfNotNull(json, 'uri', uri);
-    _setValueIfNotNull(json, 'scriptIds', scriptIds);
-    _setObjectListIfNotNull(json, 'dependencies', dependencies);
+    final json = {
+      ...super.toJson(),
+      if (name.isNotEmpty) 'name': name,
+      'uri': uri,
+      if (scriptIds.isNotEmpty) 'scriptIds': scriptIds,
+    };
+    _setObjectListIfNotNullOrEmpty(json, 'dependencies', dependencies);
     return json;
   }
 }
 
 class LibrarySymbolDependency implements SymbolTableElement {
-  /// Is this dependency an import (rather than an export)?
-  bool isImport;
+  /// True if this dependency an import, false if an an export.
+  final bool isImport;
 
-  /// Is this dependency deferred?
-  bool isDeferred;
+  /// True if this dependency is deferred.
+  final bool isDeferred;
 
   /// The prefix of an 'as' import, or null.
-  String prefix;
+  final String? prefix;
 
   /// The library being imported or exported.
-  String targetId;
+  final String targetId;
+
   LibrarySymbolDependency({
-    this.isImport,
-    this.isDeferred,
+    required this.isImport,
+    bool? isDeferred,
     this.prefix,
-    this.targetId,
-  });
-  LibrarySymbolDependency.fromJson(Map<String, dynamic> json) {
-    isImport = _createValue(json['isImport']);
-    isDeferred = _createValue(json['isDeferred']);
-    prefix = _createValue(json['prefix']);
-    targetId = _createValue(json['targetId']);
-  }
+    required this.targetId,
+  }) : isDeferred = isDeferred ?? false;
+
+  LibrarySymbolDependency.fromJson(Map<String, dynamic> json)
+      : isImport = _createValue(json['isImport']),
+        isDeferred = _createValue(json['isDeferred']),
+        prefix = _createValue(json['prefix']),
+        targetId = _createValue(json['targetId']);
+
   @override
-  Map<String, dynamic> toJson() {
-    final json = <String, dynamic>{};
-    _setValueIfNotNull(json, 'isImport', isImport);
-    _setValueIfNotNull(json, 'isDeferred', isDeferred);
-    _setValueIfNotNull(json, 'prefix', prefix);
-    _setValueIfNotNull(json, 'targetId', targetId);
-    return json;
-  }
+  Map<String, dynamic> toJson() => {
+        'isImport': isImport,
+        'isDeferred': isDeferred,
+        if (prefix != null) 'prefix': prefix,
+        'targetId': targetId,
+      };
 }
 
 class Script implements SymbolTableElement {
   /// The uri from which this script was loaded.
-  String uri;
+  final String uri;
 
   /// Unique Id.
   ///
   /// This can be just an integer. The mapping from JS to dart script
   /// happens using the source map. The id is only used for references
   /// in other elements.
-  String localId;
+  final String localId;
 
-  String libraryId;
+  final String libraryId;
 
   String get id => '$libraryId|$localId';
 
   Script({
-    this.uri,
-    this.localId,
-    this.libraryId,
+    required this.uri,
+    required this.localId,
+    required this.libraryId,
   });
-  Script.fromJson(Map<String, dynamic> json) {
-    uri = _createValue(json['uri']);
-    localId = _createValue(json['localId']);
-    libraryId = _createValue(json['libraryId']);
-  }
-  @override
-  Map<String, dynamic> toJson() {
-    final json = <String, dynamic>{};
-    _setValueIfNotNull(json, 'uri', uri);
-    _setValueIfNotNull(json, 'localId', localId);
-    _setValueIfNotNull(json, 'libraryId', libraryId);
 
-    return json;
-  }
+  Script.fromJson(Map<String, dynamic> json)
+      : uri = _createValue(json['uri']),
+        localId = _createValue(json['localId']),
+        libraryId = _createValue(json['libraryId']);
+
+  @override
+  Map<String, dynamic> toJson() => {
+        'uri': uri,
+        'localId': localId,
+        'libraryId': libraryId,
+      };
 }
 
 class ScopeSymbol extends Symbol {
   /// A list of the top-level variables in this scope.
-  List<String> variableIds;
+  final List<String> variableIds;
 
   /// Enclosed scopes.
   ///
   /// Includes all top classes, functions, inner scopes.
-  List<String> scopeIds;
+  final List<String> scopeIds;
+
   ScopeSymbol({
-    this.variableIds,
-    this.scopeIds,
-    String localId,
-    String scopeId,
-    SourceLocation location,
-  }) : super(
+    List<String>? variableIds,
+    List<String>? scopeIds,
+    required String localId,
+    String? scopeId,
+    SourceLocation? location,
+  })  : variableIds = variableIds ?? [],
+        scopeIds = scopeIds ?? [],
+        super(
           localId: localId,
           scopeId: scopeId,
           location: location,
         );
-  ScopeSymbol.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
-    variableIds = _createValueList(json['variableIds']);
-    scopeIds = _createValueList(json['scopeIds']);
-  }
+
+  ScopeSymbol.fromJson(Map<String, dynamic> json)
+      : variableIds = _createValueList(json['variableIds']),
+        scopeIds = _createValueList(json['scopeIds']),
+        super.fromJson(json);
+
   @override
-  Map<String, dynamic> toJson() {
-    final json = super.toJson();
-    _setValueIfNotNull(json, 'variableIds', variableIds);
-    _setValueIfNotNull(json, 'scopeIds', scopeIds);
-    return json;
-  }
+  Map<String, dynamic> toJson() => {
+        ...super.toJson(),
+        if (variableIds.isNotEmpty) 'variableIds': variableIds,
+        if (scopeIds.isNotEmpty) 'scopeIds': scopeIds,
+      };
 }
 
 class SourceLocation implements SymbolTableElement {
   /// The script containing the source location.
-  String scriptId;
+  final String scriptId;
 
   /// The first token of the location.
-  int tokenPos;
+  final int tokenPos;
 
   /// The last token of the location if this is a range.
-  int endTokenPos;
+  final int? endTokenPos;
+
   SourceLocation({
-    this.scriptId,
-    this.tokenPos,
+    required this.scriptId,
+    required this.tokenPos,
     this.endTokenPos,
   });
-  SourceLocation.fromJson(Map<String, dynamic> json) {
-    scriptId = _createValue(json['scriptId']);
-    tokenPos = _createValue(json['tokenPos']);
-    endTokenPos = _createValue(json['endTokenPos']);
-  }
+
+  SourceLocation.fromJson(Map<String, dynamic> json)
+      : scriptId = _createValue(json['scriptId']),
+        tokenPos = _createValue(json['tokenPos']),
+        endTokenPos = _createValue(json['endTokenPos']);
+
   @override
-  Map<String, dynamic> toJson() {
-    final json = <String, dynamic>{};
-    _setValueIfNotNull(json, 'scriptId', scriptId);
-    _setValueIfNotNull(json, 'tokenPos', tokenPos);
-    _setValueIfNotNull(json, 'endTokenPos', endTokenPos);
-    return json;
-  }
+  Map<String, dynamic> toJson() => {
+        'scriptId': scriptId,
+        'tokenPos': tokenPos,
+        if (endTokenPos != null) 'endTokenPos': endTokenPos,
+      };
 }
 
 List<T> _createObjectList<T>(
     dynamic json, T Function(Map<String, dynamic>) creator) {
-  if (json == null) return null;
+  if (json == null) return <T>[];
   if (json is List) {
     return json.map((e) => _createObject(e, creator)).toList();
   }
@@ -643,16 +688,19 @@
 }
 
 T _createObject<T>(dynamic json, T Function(Map<String, dynamic>) creator) {
-  if (json == null) return null;
   if (json is Map<String, dynamic>) {
     return creator(json);
   }
   throw ArgumentError('Not a map: $json');
 }
 
+T? _createNullableObject<T>(
+        dynamic json, T Function(Map<String, dynamic>) creator) =>
+    json == null ? null : _createObject(json, creator);
+
 List<T> _createValueList<T>(dynamic json,
-    {T ifNull, T Function(String) parse}) {
-  if (json == null) return null;
+    {T? ifNull, T Function(String)? parse}) {
+  if (json == null) return <T>[];
   if (json is List) {
     return json
         .map((e) => _createValue<T>(e, ifNull: ifNull, parse: parse))
@@ -662,12 +710,12 @@
 }
 
 Map<String, T> _createValueMap<T>(dynamic json) {
-  if (json == null) return null;
+  if (json == null) return <String, T>{};
   return Map<String, T>.from(json as Map<String, dynamic>);
 }
 
-T _createValue<T>(dynamic json, {T ifNull, T Function(String) parse}) {
-  if (json == null) return ifNull;
+T _createValue<T>(dynamic json, {T? ifNull, T Function(String)? parse}) {
+  if (json == null && ifNull is T) return ifNull;
   if (json is T) {
     return json;
   }
@@ -677,19 +725,14 @@
   throw ArgumentError('Cannot parse $json as $T');
 }
 
-void _setObjectListIfNotNull<T extends SymbolTableElement>(
-    Map<String, dynamic> json, String key, List<T> values) {
-  if (values == null) return;
-  json[key] = values.map((e) => e?.toJson()).toList();
+void _setObjectListIfNotNullOrEmpty<T extends SymbolTableElement>(
+    Map<String, dynamic> json, String key, List<T>? values) {
+  if (values == null || values.isEmpty) return;
+  json[key] = values.map((e) => e.toJson()).toList();
 }
 
 void _setObjectIfNotNull<T extends SymbolTableElement>(
-    Map<String, dynamic> json, String key, T value) {
+    Map<String, dynamic> json, String key, T? value) {
   if (value == null) return;
-  json[key] = value?.toJson();
-}
-
-void _setValueIfNotNull<T>(Map<String, dynamic> json, String key, T value) {
-  if (value == null) return;
-  json[key] = value;
+  json[key] = value.toJson();
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/module_symbols_collector.dart b/pkg/dev_compiler/lib/src/kernel/module_symbols_collector.dart
index 2b458bb..6eb1acd 100644
--- a/pkg/dev_compiler/lib/src/kernel/module_symbols_collector.dart
+++ b/pkg/dev_compiler/lib/src/kernel/module_symbols_collector.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:front_end/src/fasta/kernel/constructor_tearoff_lowering.dart'
     show isTearOffLowering;
 import 'package:kernel/kernel.dart';
@@ -25,16 +23,7 @@
 
   ModuleSymbolsCollector(String moduleName, this._classJsNames,
       this._memberJsNames, this._procedureJsNames, this._variableJsNames)
-      : _moduleSymbols = ModuleSymbols(
-            version: ModuleSymbols.current.version,
-            moduleName: moduleName,
-            libraries: <LibrarySymbol>[],
-            scripts: <Script>[],
-            classes: <ClassSymbol>[],
-            // TODO(nshahan) functionTypes
-            functions: <FunctionSymbol>[],
-            // TODO(nshahan) scopes
-            variables: <VariableSymbol>[]);
+      : _moduleSymbols = ModuleSymbols(moduleName: moduleName);
 
   ModuleSymbols collectSymbolInfo(Component node) {
     node.accept(this);
@@ -45,7 +34,9 @@
   String _scriptId(Uri fileUri) => fileUri.toString();
 
   /// Returns the id of [type].
-  String _typeId(DartType type) =>
+  // TODO(nshahan) Only nullable until we design how to identify types from
+  // other modules.
+  String? _typeId(DartType type) =>
       // TODO(nshahan) How to handle function types or types from other modules?
       type is InterfaceType ? _classJsNames[type.classNode] : null;
 
@@ -55,15 +46,14 @@
         name: node.name.text,
         // TODO(nshahan) typeId - probably should canonicalize but keep original
         // type argument names.
+        typeId: null,
         // TODO(nshahan) Should we mark all constructors static?
         isStatic: node is Procedure ? node.isStatic : false,
         isConst: node.isConst,
-        localId: _memberJsNames[node] ?? _procedureJsNames[node],
+        localId: _memberJsNames[node] ?? _procedureJsNames[node]!,
         scopeId: _scopes.last.id,
-        variableIds: <String>[],
-        scopeIds: <String>[],
         location: SourceLocation(
-            scriptId: _scriptId(node.location.file),
+            scriptId: _scriptId(node.location!.file),
             tokenPos: node.fileOffset,
             endTokenPos: node.fileEndOffset));
 
@@ -83,22 +73,19 @@
         isConst: node.constructors.any((constructor) => constructor.isConst),
         superClassId: _classJsNames[node.superclass],
         interfaceIds: [
-          for (var type in node.implementedTypes) _classJsNames[type.classNode]
+          for (var type in node.implementedTypes) _classJsNames[type.classNode]!
         ],
         typeParameters: {
           for (var param in node.typeParameters)
             // TODO(nshahan) Value should be the JS name.
-            param.name: param.name
+            param.name!: param.name!
         },
-        localId: _classJsNames[node],
+        localId: _classJsNames[node]!,
         scopeId: _scopes.last.id,
         location: SourceLocation(
-            scriptId: _scriptId(node.location.file),
+            scriptId: _scriptId(node.location!.file),
             tokenPos: node.startFileOffset,
-            endTokenPos: node.fileEndOffset),
-        // Create empty list, they are added in visitField().
-        variableIds: <String>[],
-        scopeIds: <String>[]);
+            endTokenPos: node.fileEndOffset));
 
     _scopes.add(classSymbol);
     node.visitChildren(this);
@@ -122,11 +109,12 @@
         isFinal: node.isFinal,
         isStatic: node.isStatic,
         typeId: _typeId(node.type),
-        localId: _memberJsNames[node],
+        localId: _memberJsNames[node]!,
         scopeId: _scopes.last.id,
         location: SourceLocation(
-            scriptId: _scriptId(node.location.file),
-            tokenPos: node.fileOffset));
+            scriptId: _scriptId(node.location!.file),
+            tokenPos: node.fileOffset,
+            endTokenPos: node.fileEndOffset));
     node.visitChildren(this);
     _scopes.last.variableIds.add(fieldSymbol.id);
     _moduleSymbols.variables.add(fieldSymbol);
@@ -135,18 +123,18 @@
   @override
   void visitLibrary(Library node) {
     var librarySymbol = LibrarySymbol(
-        name: node.name,
-        uri: node.importUri.toString(),
-        dependencies: [
-          for (var dep in node.dependencies)
-            LibrarySymbolDependency(
-                isImport: dep.isImport,
-                isDeferred: dep.isDeferred,
-                // TODO(nshahan) Need to handle prefixes.
-                targetId: dep.targetLibrary.importUri.toString())
-        ],
-        variableIds: <String>[],
-        scopeIds: <String>[]);
+      name: node.name,
+      uri: node.importUri.toString(),
+      dependencies: [
+        for (var dep in node.dependencies)
+          LibrarySymbolDependency(
+              isImport: dep.isImport,
+              isDeferred: dep.isDeferred,
+              // TODO(nshahan) Need to handle prefixes.
+              targetId: dep.targetLibrary.importUri.toString())
+      ],
+      scriptIds: [],
+    );
 
     // TODO(nshahan) Save some space by using integers as local ids?
     var scripts = [
@@ -161,7 +149,7 @@
             libraryId: librarySymbol.id),
     ];
 
-    librarySymbol.scriptIds = [for (var script in scripts) script.id];
+    librarySymbol.scriptIds.addAll(scripts.map((s) => s.id));
     _moduleSymbols.scripts.addAll(scripts);
 
     _scopes.add(librarySymbol);
@@ -195,16 +183,16 @@
   VariableSymbol _createVariableSymbol(
           VariableDeclaration node, VariableSymbolKind kind) =>
       VariableSymbol(
-          name: node.name,
+          name: node.name!,
           kind: kind,
           isConst: node.isConst,
           isFinal: node.isFinal,
           // Static fields are visited in `visitField()`.
           isStatic: false,
           typeId: _typeId(node.type),
-          localId: _variableJsNames[node],
+          localId: _variableJsNames[node]!,
           scopeId: _scopes.last.id,
           location: SourceLocation(
-              scriptId: _scriptId(node.location.file),
+              scriptId: _scriptId(node.location!.file),
               tokenPos: node.fileOffset));
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 7985eb6..bb79eb8 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -8,6 +8,7 @@
     show Message, LocatedMessage;
 import 'package:_js_interop_checks/js_interop_checks.dart';
 import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart';
+import 'package:_js_interop_checks/src/transformations/static_interop_class_eraser.dart';
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
@@ -188,6 +189,7 @@
       ChangedStructureNotifier? changedStructureNotifier}) {
     _nativeClasses ??= JsInteropChecks.getNativeClasses(component);
     var jsUtilOptimizer = JsUtilOptimizer(coreTypes, hierarchy);
+    var staticInteropClassEraser = StaticInteropClassEraser(coreTypes);
     for (var library in libraries) {
       _CovarianceTransformer(library).transform();
       JsInteropChecks(
@@ -196,6 +198,7 @@
               _nativeClasses!)
           .visitLibrary(library);
       jsUtilOptimizer.visitLibrary(library);
+      staticInteropClassEraser.visitLibrary(library);
     }
   }
 
diff --git a/pkg/dev_compiler/test/module_symbols/class_symbols_test.dart b/pkg/dev_compiler/test/module_symbols/class_symbols_test.dart
index e1af8a8..6ebcbba 100644
--- a/pkg/dev_compiler/test/module_symbols/class_symbols_test.dart
+++ b/pkg/dev_compiler/test/module_symbols/class_symbols_test.dart
@@ -71,12 +71,10 @@
             expect(classSymbol.location.scriptId, endsWith('/foo.dart'));
           });
           test('has start token', () async {
-            expect(classSymbol.location.tokenPos,
-                22 + options.dartLangComment.length);
+            expect(classSymbol.location.tokenPos, source.indexOf('class A'));
           });
           test('has end token', () async {
-            expect(classSymbol.location.endTokenPos,
-                31 + options.dartLangComment.length);
+            expect(classSymbol.location.endTokenPos, source.lastIndexOf('}'));
           });
         });
         test('no fields', () async {
diff --git a/pkg/dev_compiler/test/module_symbols/function_symbols_test.dart b/pkg/dev_compiler/test/module_symbols/function_symbols_test.dart
index f39f27b..9c58e06 100644
--- a/pkg/dev_compiler/test/module_symbols/function_symbols_test.dart
+++ b/pkg/dev_compiler/test/module_symbols/function_symbols_test.dart
@@ -66,11 +66,11 @@
           });
           test('has start token', () async {
             expect(functionSymbol.location.tokenPos,
-                27 + options.dartLangComment.length);
+                source.indexOf('topLevelFunction'));
           });
           test('has end token', () async {
-            expect(functionSymbol.location.endTokenPos,
-                78 + options.dartLangComment.length);
+            expect(
+                functionSymbol.location.endTokenPos, source.lastIndexOf('}'));
           });
         });
         test('id in LibrarySymbol scopes', () async {
diff --git a/pkg/dev_compiler/test/module_symbols/module_symbols_json_test.dart b/pkg/dev_compiler/test/module_symbols/module_symbols_json_test.dart
index 586f202..ad23ffd 100644
--- a/pkg/dev_compiler/test/module_symbols/module_symbols_json_test.dart
+++ b/pkg/dev_compiler/test/module_symbols/module_symbols_json_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.9
-
 import 'package:dev_compiler/src/kernel/module_symbols.dart';
 import 'package:test/test.dart';
 
@@ -26,7 +24,12 @@
 ''';
 
 void main() {
-  var intType = ClassSymbol(name: 'int', localId: 'int', scopeId: 'dart:core');
+  var intType = ClassSymbol(
+      name: 'int',
+      localId: 'int',
+      scopeId: 'dart:core',
+      location: SourceLocation(
+          scriptId: 'sdkIdForTest', tokenPos: 42, endTokenPos: 42));
 
   var libraryId = 'lib1';
   var main = Script(
@@ -243,14 +246,16 @@
 
   test('Read supported version', () {
     var version = SemanticVersion(0, 2, 3).version;
-    var json = ModuleSymbols(version: version).toJson();
+    var json = ModuleSymbols(version: version, moduleName: 'moduleNameForTest')
+        .toJson();
 
     expect(ModuleSymbols.fromJson(json).version, equals(version));
   });
 
   test('Read unsupported version', () {
     var version = SemanticVersion(1, 2, 3).version;
-    var json = ModuleSymbols(version: version).toJson();
+    var json = ModuleSymbols(version: version, moduleName: 'moduleNameForTest')
+        .toJson();
 
     expect(() => ModuleSymbols.fromJson(json), throwsException);
   });
@@ -300,7 +305,8 @@
     .having((cls) => cls.libraryId, 'libraryId', other.libraryId)
     .having((cls) => cls.scopeIds, 'scopeIds', other.scopeIds)
     .having((cls) => cls.variableIds, 'variableIds', other.variableIds)
-    .having((cls) => cls.location, 'location', matchesLocation(other.location));
+    .having(
+        (cls) => cls.location, 'location', matchesLocation(other.location!));
 
 TypeMatcher<FunctionTypeSymbol> matchesFunctionType(FunctionTypeSymbol other) =>
     isA<FunctionTypeSymbol>()
@@ -315,8 +321,8 @@
             'optionalParameterTypeIds', other.optionalParameterTypeIds)
         .having((fun) => fun.namedParameterTypeIds, 'namedParameterTypeIds',
             other.namedParameterTypeIds)
-        .having(
-            (fun) => fun.location, 'location', matchesLocation(other.location));
+        .having((fun) => fun.location, 'location',
+            matchesLocation(other.location!));
 
 TypeMatcher<FunctionSymbol> matchesFunction(FunctionSymbol other) =>
     isA<FunctionSymbol>()
@@ -329,8 +335,8 @@
         .having((fun) => fun.typeId, 'typeId', other.typeId)
         .having((fun) => fun.scopeIds, 'scopeIds', other.scopeIds)
         .having((fun) => fun.variableIds, 'variableIds', other.variableIds)
-        .having(
-            (fun) => fun.location, 'location', matchesLocation(other.location));
+        .having((fun) => fun.location, 'location',
+            matchesLocation(other.location!));
 
 TypeMatcher<ScopeSymbol> matchesScope(ScopeSymbol other) => isA<ScopeSymbol>()
     .having((scope) => scope.localId, 'localId', other.localId)
@@ -338,8 +344,8 @@
     .having((scope) => scope.id, 'id', other.id)
     .having((scope) => scope.scopeIds, 'scopeIds', other.scopeIds)
     .having((scope) => scope.variableIds, 'variableIds', other.variableIds)
-    .having(
-        (scope) => scope.location, 'location', matchesLocation(other.location));
+    .having((scope) => scope.location, 'location',
+        matchesLocation(other.location!));
 
 TypeMatcher<VariableSymbol> matchesVariable(VariableSymbol other) =>
     isA<VariableSymbol>()
@@ -351,7 +357,7 @@
         .having((variable) => variable.isStatic, 'isStatic', other.isStatic)
         .having((variable) => variable.isFinal, 'isFinal', other.isFinal)
         .having((variable) => variable.location, 'location',
-            matchesLocation(other.location));
+            matchesLocation(other.location!));
 
 TypeMatcher<Script> matchesScript(Script other) => isA<Script>()
     .having((script) => script.uri, 'uri', other.uri)
diff --git a/pkg/dev_compiler/test/module_symbols/variable_symbols_test.dart b/pkg/dev_compiler/test/module_symbols/variable_symbols_test.dart
index 64b3e57..b6421d1 100644
--- a/pkg/dev_compiler/test/module_symbols/variable_symbols_test.dart
+++ b/pkg/dev_compiler/test/module_symbols/variable_symbols_test.dart
@@ -62,10 +62,13 @@
           test('has scriptId', () async {
             expect(variableSymbol.location.scriptId, endsWith('/foo.dart'));
           });
-          test('only start token', () async {
+          test('start token position', () async {
             expect(variableSymbol.location.tokenPos,
-                47 + options.dartLangComment.length);
-            expect(variableSymbol.location.endTokenPos, null);
+                source.indexOf('globalVariable'));
+          });
+          test('end token position', () async {
+            expect(
+                variableSymbol.location.endTokenPos, source.lastIndexOf(';'));
           });
         });
       });
diff --git a/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.modular.expect
new file mode 100644
index 0000000..46e4364
--- /dev/null
+++ b/pkg/front_end/testcases/dart2js/constructor_tearoff.dart.weak.modular.expect
@@ -0,0 +1,46 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef Alias<T extends core::num> = self::Class<T>;
+class Class<T extends core::Object? = dynamic> extends core::Object {
+  static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
+  constructor •() → self::Class<self::Class::T%>
+    : super core::Object::•()
+    ;
+  static method _#new#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#new#tearOff::T%>
+    return new self::Class::•<self::Class::_#new#tearOff::T%>();
+  static factory fact<T extends core::Object? = dynamic>() → self::Class<self::Class::fact::T%>
+    return new self::Class::•<self::Class::fact::T%>();
+  static method _#fact#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#fact#tearOff::T%>
+    return self::Class::fact<self::Class::_#fact#tearOff::T%>();
+  static factory redirect<T extends core::Object? = dynamic>() → self::Class<self::Class::redirect::T%>
+    return new self::Class::•<self::Class::redirect::T%>();
+  static method _#redirect#tearOff<T extends core::Object? = dynamic>() → self::Class<self::Class::_#redirect#tearOff::T%>
+    return new self::Class::•<self::Class::_#redirect#tearOff::T%>();
+}
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> a = #C2;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> b = #C3;
+static const field <T extends core::Object? = dynamic>() → self::Class<T%> c = #C4;
+static const field <T extends core::num>() → self::Class<T> d = #C5;
+static const field <T extends core::num>() → self::Class<T> e = #C6;
+static const field <T extends core::num>() → self::Class<T> f = #C7;
+static method main() → dynamic {
+  core::print("${#C2}${#C3}${#C4}${#C5}${#C6}${#C7}");
+}
+static method _#Alias#new#tearOff<T extends core::num>() → self::Class<self::_#Alias#new#tearOff::T>
+  return new self::Class::•<self::_#Alias#new#tearOff::T>();
+static method _#Alias#fact#tearOff<T extends core::num>() → self::Class<self::_#Alias#fact#tearOff::T>
+  return self::Class::fact<self::_#Alias#fact#tearOff::T>();
+static method _#Alias#redirect#tearOff<T extends core::num>() → self::Class<self::_#Alias#redirect#tearOff::T>
+  return self::Class::_#redirect#tearOff<self::_#Alias#redirect#tearOff::T>();
+
+constants  {
+  #C1 = constructor-tearoff self::Class::redirect
+  #C2 = static-tearoff self::Class::_#new#tearOff
+  #C3 = static-tearoff self::Class::_#fact#tearOff
+  #C4 = static-tearoff self::Class::_#redirect#tearOff
+  #C5 = static-tearoff self::_#Alias#new#tearOff
+  #C6 = static-tearoff self::_#Alias#fact#tearOff
+  #C7 = static-tearoff self::_#Alias#redirect#tearOff
+}
diff --git a/pkg/front_end/testcases/super_parameters/simple_positional_super_parameters.dart.weak.modular.expect b/pkg/front_end/testcases/super_parameters/simple_positional_super_parameters.dart.weak.modular.expect
new file mode 100644
index 0000000..630145e
--- /dev/null
+++ b/pkg/front_end/testcases/super_parameters/simple_positional_super_parameters.dart.weak.modular.expect
@@ -0,0 +1,31 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/super_parameters/simple_positional_super_parameters.dart:15:23: Error: Positional super-initializer parameters cannot be used when the super initializer has positional arguments.
+//   C(super.foo) : super(42); // Error.
+//                       ^
+// pkg/front_end/testcases/super_parameters/simple_positional_super_parameters.dart:15:11: Context: This is the super-initializer parameter.
+//   C(super.foo) : super(42); // Error.
+//           ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  final field core::int foo;
+  constructor •(core::int foo) → self::A
+    : self::A::foo = foo, super core::Object::•()
+    ;
+}
+class B extends self::A {
+  constructor •(dynamic foo) → self::B
+    : super self::A::•(foo as{TypeError,ForDynamic,ForNonNullableByDefault} core::int)
+    ;
+}
+class C extends self::A {
+  constructor •(dynamic foo) → self::C
+    : super self::A::•(42)
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/js/lib/js.dart b/pkg/js/lib/js.dart
index 1c099c3..5f41532 100644
--- a/pkg/js/lib/js.dart
+++ b/pkg/js/lib/js.dart
@@ -25,9 +25,9 @@
   const _Anonymous();
 }
 
-// class _StaticInterop {
-//   const _StaticInterop();
-// }
+class _StaticInterop {
+  const _StaticInterop();
+}
 
 /// An annotation that indicates a [JS] annotated class is structural and does
 /// not have a known JavaScript prototype.
@@ -44,6 +44,4 @@
 /// These classes allow interop with native types, like the ones in `dart:html`.
 /// These classes should not contain any instance members, inherited or
 /// otherwise, and should instead use static extension members.
-// TODO(47324, 47325): Uncomment these annotations once erasure and subtyping
-// are ready.
-// const _StaticInterop staticInterop = _StaticInterop();
+const _StaticInterop staticInterop = _StaticInterop();
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/js_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/js_patch.dart
index 033b303..96a972f 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/js_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/js_patch.dart
@@ -9,7 +9,7 @@
 
 import 'dart:_js_helper' show patch, NoReifyGeneric, Primitives;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show JavaScriptObject;
+import 'dart:_interceptors' show LegacyJavaScriptObject;
 import 'dart:_runtime' as dart;
 
 @patch
@@ -368,7 +368,8 @@
     int ms = JS('!', '#.getTime()', o);
     return DateTime.fromMillisecondsSinceEpoch(ms);
   } else if (o is _DartObject &&
-      !identical(dart.getReifiedType(o), dart.typeRep<JavaScriptObject>())) {
+      !identical(
+          dart.getReifiedType(o), dart.typeRep<LegacyJavaScriptObject>())) {
     return o._dartObj;
   } else {
     return _wrapToDart(o);
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
index 9e99b26..f359d52 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
@@ -92,13 +92,13 @@
         return JS('', '#.constructor', obj);
       }
       var result = JS('', '#[#]', obj, _extensionType);
-      if (result == null) return typeRep<JavaScriptObject>();
+      if (result == null) return typeRep<LegacyJavaScriptObject>();
       return result;
     case "function":
       // All Dart functions and callable classes must set _runtimeType
       var result = JS('', '#[#]', obj, _runtimeType);
       if (result != null) return result;
-      return typeRep<JavaScriptObject>();
+      return typeRep<LegacyJavaScriptObject>();
     case "undefined":
       return JS('', '#', Null);
     case "number":
@@ -109,7 +109,7 @@
       return JS('', '#', String);
     case "symbol":
     default:
-      return typeRep<JavaScriptObject>();
+      return typeRep<LegacyJavaScriptObject>();
   }
 }
 
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
index c5881ab..af599c3 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
@@ -11,7 +11,7 @@
 import 'dart:_debugger' show stackTraceMapper, trackCall;
 import 'dart:_foreign_helper' show JS, JSExportName, rest, spread;
 import 'dart:_interceptors'
-    show JSArray, jsNull, JSFunction, NativeError, JavaScriptObject;
+    show JSArray, jsNull, JSFunction, NativeError, LegacyJavaScriptObject;
 import 'dart:_internal' as internal show LateError, Symbol;
 import 'dart:_js_helper'
     show
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index 9904b5c..9452ed3 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -164,7 +164,7 @@
 
 @notNull
 bool _isJsObject(obj) =>
-    JS('!', '# === #', getReifiedType(obj), typeRep<JavaScriptObject>());
+    JS('!', '# === #', getReifiedType(obj), typeRep<LegacyJavaScriptObject>());
 
 /// Asserts that [f] is a native JS functions and returns it if so.
 ///
@@ -1503,16 +1503,17 @@
     }
 
     // Even though lazy and anonymous JS types are natural subtypes of
-    // JavaScriptObject, JS types should be treated as mutual subtypes of each
-    // other. This allows users to be able to interface with both extension
-    // types on JavaScriptObject and package:js using the same object.
+    // LegacyJavaScriptObject, JS types should be treated as mutual subtypes of
+    // each other. This allows users to be able to interface with both extension
+    // types on LegacyJavaScriptObject and package:js using the same object.
     //
     // Therefore, the following relationships hold true:
     //
-    // JavaScriptObject <: package:js types
-    // package:js types <: JavaScriptObject
+    // LegacyJavaScriptObject <: package:js types
+    // package:js types <: LegacyJavaScriptObject
 
-    if (_isInterfaceSubtype(t1, typeRep<JavaScriptObject>(), strictMode) &&
+    if (_isInterfaceSubtype(
+            t1, typeRep<LegacyJavaScriptObject>(), strictMode) &&
         // TODO: Since package:js types are instances of PackageJSType and
         // we don't have a mechanism to determine if *some* package:js type
         // implements t2. This will possibly require keeping a map of these
@@ -1522,7 +1523,8 @@
       return true;
     }
 
-    if (_isInterfaceSubtype(typeRep<JavaScriptObject>(), t2, strictMode) &&
+    if (_isInterfaceSubtype(
+            typeRep<LegacyJavaScriptObject>(), t2, strictMode) &&
         _isInterfaceSubtype(t1, _pkgJSTypeForSubtyping, strictMode)) {
       return true;
     }
diff --git a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
index 01921c0..8e700e5 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
@@ -81,14 +81,21 @@
 /// interop library.
 abstract class JSObject {}
 
+/// Superclass of all interop objects and native types defined in the web
+/// libraries.
+///
+/// This is the class static interop classes erase to and the class interop
+/// extension types should use as the on-type.
+class JavaScriptObject extends Interceptor {
+  const JavaScriptObject();
+}
+
 /// Interceptor base class for JavaScript objects not recognized as some more
 /// specific native type.
-
-/// Unlike dart2js, ddc does not intercept JS objects, so this is only used as
-/// an on-type for JS interop extension types. All JS interop objects should be
-/// castable to this type.
-abstract class JavaScriptObject extends Interceptor implements JSObject {
-  const JavaScriptObject();
+///
+/// Note that this used to be `JavaScriptObject`.
+class LegacyJavaScriptObject extends JavaScriptObject implements JSObject {
+  const LegacyJavaScriptObject();
 }
 
 /// Interceptor for plain JavaScript objects created as JavaScript object
@@ -96,7 +103,7 @@
 ///
 /// Note that this isn't being used today in ddc. Instead of using interceptors,
 /// we have other type logic to distinguish JS types.
-class PlainJavaScriptObject extends JavaScriptObject {
+class PlainJavaScriptObject extends LegacyJavaScriptObject {
   const PlainJavaScriptObject();
 }
 
@@ -106,7 +113,7 @@
 /// This class also serves as a fallback for unknown JavaScript exceptions.
 /// Note that this isn't being used today in ddc. Instead of using interceptors,
 /// we have other type logic to distinguish JS types.
-class UnknownJavaScriptObject extends JavaScriptObject {
+class UnknownJavaScriptObject extends LegacyJavaScriptObject {
   const UnknownJavaScriptObject();
 }
 
diff --git a/sdk/lib/_internal/js_runtime/lib/interceptors.dart b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
index 5a062ab..bda0ac3 100644
--- a/sdk/lib/_internal/js_runtime/lib/interceptors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
@@ -399,16 +399,28 @@
   operator []=(int index, E value);
 }
 
-/// The interface implemented by JavaScript objects.  These are methods in
-/// addition to the regular Dart Object methods like [Object.hashCode].
+/// The interface implemented by JavaScript objects.
 ///
-/// This is the type that should be exported by a JavaScript interop library.
+/// These are methods in addition to the regular Dart Object methods like
+/// [Object.hashCode]. This is the type that should be exported by a JavaScript
+/// interop library.
 abstract class JSObject {}
 
+/// Superclass of all interop objects and native types defined in the web
+/// libraries.
+///
+/// This is the class static interop classes erase to and the class interop
+/// extension types should use as the on-type.
+class JavaScriptObject extends Interceptor {
+  const JavaScriptObject();
+}
+
 /// Interceptor base class for JavaScript objects not recognized as some more
 /// specific native type.
-class JavaScriptObject extends Interceptor implements JSObject {
-  const JavaScriptObject();
+///
+/// Note that this used to be `JavaScriptObject`.
+class LegacyJavaScriptObject extends JavaScriptObject implements JSObject {
+  const LegacyJavaScriptObject();
 
   // It would be impolite to stash a property on the object.
   int get hashCode => 0;
@@ -421,7 +433,7 @@
 
 /// Interceptor for plain JavaScript objects created as JavaScript object
 /// literals or `new Object()`.
-class PlainJavaScriptObject extends JavaScriptObject {
+class PlainJavaScriptObject extends LegacyJavaScriptObject {
   const PlainJavaScriptObject();
 }
 
@@ -429,7 +441,7 @@
 /// non-trivial prototype chain.
 ///
 /// This class also serves as a fallback for unknown JavaScript exceptions.
-class UnknownJavaScriptObject extends JavaScriptObject {
+class UnknownJavaScriptObject extends LegacyJavaScriptObject {
   const UnknownJavaScriptObject();
 }
 
@@ -437,7 +449,7 @@
 /// been converted to JavaScript functions.
 /// These interceptor methods are not always used as the JavaScript function
 /// object has also been mangled to support Dart function calling conventions.
-class JavaScriptFunction extends JavaScriptObject implements Function {
+class JavaScriptFunction extends LegacyJavaScriptObject implements Function {
   const JavaScriptFunction();
 
   String toString() {
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index cc93c1e..448b653 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -57,7 +57,7 @@
         applyExtension;
 import 'dart:_interceptors'
     show
-        Interceptor,
+        JavaScriptObject,
         JavaScriptFunction,
         JSExtendableArray,
         JSUInt31,
@@ -176,7 +176,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class AbstractWorker extends Interceptor implements EventTarget {
+abstract class AbstractWorker extends JavaScriptObject implements EventTarget {
   // To suppress missing implicit constructor warnings.
   factory AbstractWorker._() {
     throw new UnsupportedError("Not supported");
@@ -469,7 +469,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AccessibleNodeList")
-class AccessibleNodeList extends Interceptor {
+class AccessibleNodeList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AccessibleNodeList._() {
     throw new UnsupportedError("Not supported");
@@ -705,7 +705,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AnimationEffectReadOnly")
-class AnimationEffectReadOnly extends Interceptor {
+class AnimationEffectReadOnly extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimationEffectReadOnly._() {
     throw new UnsupportedError("Not supported");
@@ -785,7 +785,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AnimationEffectTimingReadOnly")
-class AnimationEffectTimingReadOnly extends Interceptor {
+class AnimationEffectTimingReadOnly extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimationEffectTimingReadOnly._() {
     throw new UnsupportedError("Not supported");
@@ -869,7 +869,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AnimationTimeline")
-class AnimationTimeline extends Interceptor {
+class AnimationTimeline extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimationTimeline._() {
     throw new UnsupportedError("Not supported");
@@ -1226,7 +1226,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AuthenticatorResponse")
-class AuthenticatorResponse extends Interceptor {
+class AuthenticatorResponse extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AuthenticatorResponse._() {
     throw new UnsupportedError("Not supported");
@@ -1329,7 +1329,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BackgroundFetchFetch")
-class BackgroundFetchFetch extends Interceptor {
+class BackgroundFetchFetch extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory BackgroundFetchFetch._() {
     throw new UnsupportedError("Not supported");
@@ -1342,7 +1342,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BackgroundFetchManager")
-class BackgroundFetchManager extends Interceptor {
+class BackgroundFetchManager extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory BackgroundFetchManager._() {
     throw new UnsupportedError("Not supported");
@@ -1449,7 +1449,7 @@
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#barprop
 @deprecated // standard
 @Native("BarProp")
-class BarProp extends Interceptor {
+class BarProp extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory BarProp._() {
     throw new UnsupportedError("Not supported");
@@ -1462,7 +1462,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BarcodeDetector")
-class BarcodeDetector extends Interceptor {
+class BarcodeDetector extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory BarcodeDetector._() {
     throw new UnsupportedError("Not supported");
@@ -1582,7 +1582,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Blob")
-class Blob extends Interceptor {
+class Blob extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Blob._() {
     throw new UnsupportedError("Not supported");
@@ -1649,7 +1649,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BluetoothRemoteGATTDescriptor")
-class BluetoothRemoteGattDescriptor extends Interceptor {
+class BluetoothRemoteGattDescriptor extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory BluetoothRemoteGattDescriptor._() {
     throw new UnsupportedError("Not supported");
@@ -1671,7 +1671,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Body")
-class Body extends Interceptor {
+class Body extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Body._() {
     throw new UnsupportedError("Not supported");
@@ -1896,7 +1896,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BudgetState")
-class BudgetState extends Interceptor {
+class BudgetState extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory BudgetState._() {
     throw new UnsupportedError("Not supported");
@@ -2006,7 +2006,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CacheStorage")
-class CacheStorage extends Interceptor {
+class CacheStorage extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CacheStorage._() {
     throw new UnsupportedError("Not supported");
@@ -2299,7 +2299,7 @@
  * * [CanvasGradient](http://www.w3.org/TR/2010/WD-2dcontext-20100304/#canvasgradient) from W3C.
  */
 @Native("CanvasGradient")
-class CanvasGradient extends Interceptor {
+class CanvasGradient extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CanvasGradient._() {
     throw new UnsupportedError("Not supported");
@@ -2350,7 +2350,7 @@
  * * [CanvasPattern](http://www.w3.org/TR/2010/WD-2dcontext-20100304/#canvaspattern) from W3C.
  */
 @Native("CanvasPattern")
-class CanvasPattern extends Interceptor {
+class CanvasPattern extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CanvasPattern._() {
     throw new UnsupportedError("Not supported");
@@ -2367,7 +2367,7 @@
 }
 
 @Native("CanvasRenderingContext2D")
-class CanvasRenderingContext2D extends Interceptor
+class CanvasRenderingContext2D extends JavaScriptObject
     implements CanvasRenderingContext {
   // To suppress missing implicit constructor warnings.
   factory CanvasRenderingContext2D._() {
@@ -3017,7 +3017,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class ChildNode extends Interceptor {
+abstract class ChildNode extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ChildNode._() {
     throw new UnsupportedError("Not supported");
@@ -3034,7 +3034,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Client")
-class Client extends Interceptor {
+class Client extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Client._() {
     throw new UnsupportedError("Not supported");
@@ -3055,7 +3055,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Clients")
-class Clients extends Interceptor {
+class Clients extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Clients._() {
     throw new UnsupportedError("Not supported");
@@ -3232,7 +3232,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CookieStore")
-class CookieStore extends Interceptor {
+class CookieStore extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CookieStore._() {
     throw new UnsupportedError("Not supported");
@@ -3260,7 +3260,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Coordinates")
-class Coordinates extends Interceptor {
+class Coordinates extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Coordinates._() {
     throw new UnsupportedError("Not supported");
@@ -3285,7 +3285,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Credential")
-class Credential extends Interceptor {
+class Credential extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Credential._() {
     throw new UnsupportedError("Not supported");
@@ -3300,7 +3300,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CredentialUserData")
-class CredentialUserData extends Interceptor {
+class CredentialUserData extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CredentialUserData._() {
     throw new UnsupportedError("Not supported");
@@ -3316,7 +3316,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CredentialsContainer")
-class CredentialsContainer extends Interceptor {
+class CredentialsContainer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CredentialsContainer._() {
     throw new UnsupportedError("Not supported");
@@ -3356,7 +3356,7 @@
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.SAFARI)
 @Native("Crypto")
-class Crypto extends Interceptor {
+class Crypto extends JavaScriptObject {
   TypedData getRandomValues(TypedData array) {
     return _getRandomValues(array);
   }
@@ -3382,7 +3382,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CryptoKey")
-class CryptoKey extends Interceptor {
+class CryptoKey extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CryptoKey._() {
     throw new UnsupportedError("Not supported");
@@ -3402,7 +3402,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CSS")
-class Css extends Interceptor {
+class Css extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Css._() {
     throw new UnsupportedError("Not supported");
@@ -3850,7 +3850,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CSSRule")
-class CssRule extends Interceptor {
+class CssRule extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CssRule._() {
     throw new UnsupportedError("Not supported");
@@ -3960,7 +3960,8 @@
 //   CSSPropertyNames.in
 
 @Native("CSSStyleDeclaration,MSStyleCSSProperties,CSS2Properties")
-class CssStyleDeclaration extends Interceptor with CssStyleDeclarationBase {
+class CssStyleDeclaration extends JavaScriptObject
+    with CssStyleDeclarationBase {
   factory CssStyleDeclaration() => new CssStyleDeclaration.css('');
 
   factory CssStyleDeclaration.css(String css) {
@@ -8725,7 +8726,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CSSStyleValue")
-class CssStyleValue extends Interceptor {
+class CssStyleValue extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CssStyleValue._() {
     throw new UnsupportedError("Not supported");
@@ -8749,7 +8750,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CSSTransformComponent")
-class CssTransformComponent extends Interceptor {
+class CssTransformComponent extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CssTransformComponent._() {
     throw new UnsupportedError("Not supported");
@@ -8880,7 +8881,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CSSVariableReferenceValue")
-class CssVariableReferenceValue extends Interceptor {
+class CssVariableReferenceValue extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CssVariableReferenceValue._() {
     throw new UnsupportedError("Not supported");
@@ -8936,7 +8937,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CustomElementRegistry")
-class CustomElementRegistry extends Interceptor {
+class CustomElementRegistry extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CustomElementRegistry._() {
     throw new UnsupportedError("Not supported");
@@ -9104,7 +9105,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DataTransfer")
-class DataTransfer extends Interceptor {
+class DataTransfer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DataTransfer._() {
     throw new UnsupportedError("Not supported");
@@ -9144,7 +9145,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DataTransferItem")
-class DataTransferItem extends Interceptor {
+class DataTransferItem extends JavaScriptObject {
   Entry getAsEntry() {
     Entry entry = _webkitGetAsEntry() as Entry;
 
@@ -9179,7 +9180,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DataTransferItemList")
-class DataTransferItemList extends Interceptor {
+class DataTransferItemList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DataTransferItemList._() {
     throw new UnsupportedError("Not supported");
@@ -9298,7 +9299,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DeprecatedStorageInfo")
-class DeprecatedStorageInfo extends Interceptor {
+class DeprecatedStorageInfo extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DeprecatedStorageInfo._() {
     throw new UnsupportedError("Not supported");
@@ -9321,7 +9322,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DeprecatedStorageQuota")
-class DeprecatedStorageQuota extends Interceptor {
+class DeprecatedStorageQuota extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DeprecatedStorageQuota._() {
     throw new UnsupportedError("Not supported");
@@ -9385,7 +9386,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DetectedBarcode")
-class DetectedBarcode extends Interceptor {
+class DetectedBarcode extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DetectedBarcode._() {
     throw new UnsupportedError("Not supported");
@@ -9408,7 +9409,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DetectedFace")
-class DetectedFace extends Interceptor {
+class DetectedFace extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DetectedFace._() {
     throw new UnsupportedError("Not supported");
@@ -9428,7 +9429,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DetectedText")
-class DetectedText extends Interceptor {
+class DetectedText extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DetectedText._() {
     throw new UnsupportedError("Not supported");
@@ -9450,7 +9451,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DeviceAcceleration")
-class DeviceAcceleration extends Interceptor {
+class DeviceAcceleration extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DeviceAcceleration._() {
     throw new UnsupportedError("Not supported");
@@ -9532,7 +9533,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DeviceRotationRate")
-class DeviceRotationRate extends Interceptor {
+class DeviceRotationRate extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DeviceRotationRate._() {
     throw new UnsupportedError("Not supported");
@@ -9742,7 +9743,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DirectoryReader")
-class DirectoryReader extends Interceptor {
+class DirectoryReader extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DirectoryReader._() {
     throw new UnsupportedError("Not supported");
@@ -10584,7 +10585,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DocumentOrShadowRoot")
-class DocumentOrShadowRoot extends Interceptor {
+class DocumentOrShadowRoot extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DocumentOrShadowRoot._() {
     throw new UnsupportedError("Not supported");
@@ -10634,7 +10635,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMError")
-class DomError extends Interceptor {
+class DomError extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomError._() {
     throw new UnsupportedError("Not supported");
@@ -10660,7 +10661,7 @@
 
 @Unstable()
 @Native("DOMException")
-class DomException extends Interceptor {
+class DomException extends JavaScriptObject {
   static const String INDEX_SIZE = 'IndexSizeError';
   static const String HIERARCHY_REQUEST = 'HierarchyRequestError';
   static const String WRONG_DOCUMENT = 'WrongDocumentError';
@@ -10719,7 +10720,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMImplementation")
-class DomImplementation extends Interceptor {
+class DomImplementation extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomImplementation._() {
     throw new UnsupportedError("Not supported");
@@ -10741,7 +10742,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Iterator")
-class DomIterator extends Interceptor {
+class DomIterator extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomIterator._() {
     throw new UnsupportedError("Not supported");
@@ -10976,7 +10977,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMMatrixReadOnly")
-class DomMatrixReadOnly extends Interceptor {
+class DomMatrixReadOnly extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomMatrixReadOnly._() {
     throw new UnsupportedError("Not supported");
@@ -11122,7 +11123,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMParser")
-class DomParser extends Interceptor {
+class DomParser extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomParser._() {
     throw new UnsupportedError("Not supported");
@@ -11215,7 +11216,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMPointReadOnly")
-class DomPointReadOnly extends Interceptor {
+class DomPointReadOnly extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomPointReadOnly._() {
     throw new UnsupportedError("Not supported");
@@ -11286,7 +11287,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMQuad")
-class DomQuad extends Interceptor {
+class DomQuad extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomQuad._() {
     throw new UnsupportedError("Not supported");
@@ -11366,7 +11367,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ClientRectList,DOMRectList")
-class DomRectList extends Interceptor
+class DomRectList extends JavaScriptObject
     with ListMixin<Rectangle>, ImmutableListMixin<Rectangle>
     implements List<Rectangle>, JavaScriptIndexingBehavior<Rectangle> {
   // To suppress missing implicit constructor warnings.
@@ -11426,7 +11427,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMRectReadOnly")
-class DomRectReadOnly extends Interceptor implements Rectangle {
+class DomRectReadOnly extends JavaScriptObject implements Rectangle {
   // NOTE! All code below should be common with RectangleBase.
   String toString() {
     return 'Rectangle ($left, $top) $width x $height';
@@ -11616,7 +11617,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMStringList")
-class DomStringList extends Interceptor
+class DomStringList extends JavaScriptObject
     with ListMixin<String>, ImmutableListMixin<String>
     implements List<String>, JavaScriptIndexingBehavior<String> {
   // To suppress missing implicit constructor warnings.
@@ -11676,7 +11677,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMStringMap")
-class DomStringMap extends Interceptor {
+class DomStringMap extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomStringMap._() {
     throw new UnsupportedError("Not supported");
@@ -11693,7 +11694,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DOMTokenList")
-class DomTokenList extends Interceptor {
+class DomTokenList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DomTokenList._() {
     throw new UnsupportedError("Not supported");
@@ -15318,7 +15319,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Entry")
-class Entry extends Interceptor {
+class Entry extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Entry._() {
     throw new UnsupportedError("Not supported");
@@ -15474,7 +15475,7 @@
 // WARNING: Do not edit - generated code.
 
 @Native("Event,InputEvent,SubmitEvent")
-class Event extends Interceptor {
+class Event extends JavaScriptObject {
   // In JS, canBubble and cancelable are technically required parameters to
   // init*Event. In practice, though, if they aren't provided they simply
   // default to false (since that's Boolean(undefined)).
@@ -15781,7 +15782,7 @@
  * for compile-time type checks and a more concise API.
  */
 @Native("EventTarget")
-class EventTarget extends Interceptor {
+class EventTarget extends JavaScriptObject {
   // Custom element created callback.
   EventTarget._created();
 
@@ -15881,7 +15882,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("External")
-class External extends Interceptor {
+class External extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory External._() {
     throw new UnsupportedError("Not supported");
@@ -15896,7 +15897,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("FaceDetector")
-class FaceDetector extends Interceptor {
+class FaceDetector extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory FaceDetector._() {
     throw new UnsupportedError("Not supported");
@@ -16120,7 +16121,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("FileList")
-class FileList extends Interceptor
+class FileList extends JavaScriptObject
     with ListMixin<File>, ImmutableListMixin<File>
     implements List<File>, JavaScriptIndexingBehavior<File> {
   // To suppress missing implicit constructor warnings.
@@ -16296,7 +16297,7 @@
 
 @SupportedBrowser(SupportedBrowser.CHROME)
 @Native("DOMFileSystem")
-class FileSystem extends Interceptor {
+class FileSystem extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory FileSystem._() {
     throw new UnsupportedError("Not supported");
@@ -16462,7 +16463,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("FontFace")
-class FontFace extends Interceptor {
+class FontFace extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory FontFace._() {
     throw new UnsupportedError("Not supported");
@@ -16595,7 +16596,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("FontFaceSource")
-class FontFaceSource extends Interceptor {
+class FontFaceSource extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory FontFaceSource._() {
     throw new UnsupportedError("Not supported");
@@ -16636,7 +16637,7 @@
 @SupportedBrowser(SupportedBrowser.IE, '10')
 @SupportedBrowser(SupportedBrowser.SAFARI)
 @Native("FormData")
-class FormData extends Interceptor {
+class FormData extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory FormData._() {
     throw new UnsupportedError("Not supported");
@@ -16770,7 +16771,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Gamepad")
-class Gamepad extends Interceptor {
+class Gamepad extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Gamepad._() {
     throw new UnsupportedError("Not supported");
@@ -16803,7 +16804,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("GamepadButton")
-class GamepadButton extends Interceptor {
+class GamepadButton extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory GamepadButton._() {
     throw new UnsupportedError("Not supported");
@@ -16845,7 +16846,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("GamepadPose")
-class GamepadPose extends Interceptor {
+class GamepadPose extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory GamepadPose._() {
     throw new UnsupportedError("Not supported");
@@ -16873,7 +16874,7 @@
 
 @Unstable()
 @Native("Geolocation")
-class Geolocation extends Interceptor {
+class Geolocation extends JavaScriptObject {
   Future<Geoposition> getCurrentPosition(
       {bool? enableHighAccuracy, Duration? timeout, Duration? maximumAge}) {
     var options = {};
@@ -17035,7 +17036,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Position,GeolocationPosition")
-class Geoposition extends Interceptor {
+class Geoposition extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Geoposition._() {
     throw new UnsupportedError("Not supported");
@@ -17486,7 +17487,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Headers")
-class Headers extends Interceptor {
+class Headers extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Headers._() {
     throw new UnsupportedError("Not supported");
@@ -17559,7 +17560,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("History")
-class History extends Interceptor implements HistoryBase {
+class History extends JavaScriptObject implements HistoryBase {
   /**
    * Checks if the State APIs are supported on the current platform.
    *
@@ -17633,7 +17634,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("HTMLCollection")
-class HtmlCollection extends Interceptor
+class HtmlCollection extends JavaScriptObject
     with ListMixin<Node>, ImmutableListMixin<Node>
     implements List<Node>, JavaScriptIndexingBehavior<Node> {
   // To suppress missing implicit constructor warnings.
@@ -17891,7 +17892,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("HTMLHyperlinkElementUtils")
-class HtmlHyperlinkElementUtils extends Interceptor {
+class HtmlHyperlinkElementUtils extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory HtmlHyperlinkElementUtils._() {
     throw new UnsupportedError("Not supported");
@@ -18815,7 +18816,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("IdleDeadline")
-class IdleDeadline extends Interceptor {
+class IdleDeadline extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory IdleDeadline._() {
     throw new UnsupportedError("Not supported");
@@ -18837,7 +18838,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ImageBitmap")
-class ImageBitmap extends Interceptor {
+class ImageBitmap extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ImageBitmap._() {
     throw new UnsupportedError("Not supported");
@@ -18854,7 +18855,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ImageBitmapRenderingContext")
-class ImageBitmapRenderingContext extends Interceptor {
+class ImageBitmapRenderingContext extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ImageBitmapRenderingContext._() {
     throw new UnsupportedError("Not supported");
@@ -18869,7 +18870,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ImageCapture")
-class ImageCapture extends Interceptor {
+class ImageCapture extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ImageCapture._() {
     throw new UnsupportedError("Not supported");
@@ -18912,7 +18913,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ImageData")
-class ImageData extends Interceptor {
+class ImageData extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ImageData._() {
     throw new UnsupportedError("Not supported");
@@ -19033,7 +19034,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("InputDeviceCapabilities")
-class InputDeviceCapabilities extends Interceptor {
+class InputDeviceCapabilities extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory InputDeviceCapabilities._() {
     throw new UnsupportedError("Not supported");
@@ -19889,7 +19890,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("IntersectionObserver")
-class IntersectionObserver extends Interceptor {
+class IntersectionObserver extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory IntersectionObserver._() {
     throw new UnsupportedError("Not supported");
@@ -19940,7 +19941,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("IntersectionObserverEntry")
-class IntersectionObserverEntry extends Interceptor {
+class IntersectionObserverEntry extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory IntersectionObserverEntry._() {
     throw new UnsupportedError("Not supported");
@@ -20356,7 +20357,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Location")
-class Location extends Interceptor implements LocationBase {
+class Location extends JavaScriptObject implements LocationBase {
   // To suppress missing implicit constructor warnings.
   factory Location._() {
     throw new UnsupportedError("Not supported");
@@ -20481,7 +20482,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaCapabilities")
-class MediaCapabilities extends Interceptor {
+class MediaCapabilities extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaCapabilities._() {
     throw new UnsupportedError("Not supported");
@@ -20510,7 +20511,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaCapabilitiesInfo")
-class MediaCapabilitiesInfo extends Interceptor {
+class MediaCapabilitiesInfo extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaCapabilitiesInfo._() {
     throw new UnsupportedError("Not supported");
@@ -20527,7 +20528,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaDeviceInfo")
-class MediaDeviceInfo extends Interceptor {
+class MediaDeviceInfo extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaDeviceInfo._() {
     throw new UnsupportedError("Not supported");
@@ -20764,7 +20765,7 @@
 
 @Unstable()
 @Native("MediaError")
-class MediaError extends Interceptor {
+class MediaError extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaError._() {
     throw new UnsupportedError("Not supported");
@@ -20850,7 +20851,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaKeyStatusMap")
-class MediaKeyStatusMap extends Interceptor {
+class MediaKeyStatusMap extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaKeyStatusMap._() {
     throw new UnsupportedError("Not supported");
@@ -20867,7 +20868,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaKeySystemAccess")
-class MediaKeySystemAccess extends Interceptor {
+class MediaKeySystemAccess extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaKeySystemAccess._() {
     throw new UnsupportedError("Not supported");
@@ -20890,7 +20891,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaKeys")
-class MediaKeys extends Interceptor {
+class MediaKeys extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaKeys._() {
     throw new UnsupportedError("Not supported");
@@ -20911,7 +20912,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaKeysPolicy")
-class MediaKeysPolicy extends Interceptor {
+class MediaKeysPolicy extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaKeysPolicy._() {
     throw new UnsupportedError("Not supported");
@@ -20932,7 +20933,7 @@
 
 @Unstable()
 @Native("MediaList")
-class MediaList extends Interceptor {
+class MediaList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaList._() {
     throw new UnsupportedError("Not supported");
@@ -20955,7 +20956,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaMetadata")
-class MediaMetadata extends Interceptor {
+class MediaMetadata extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaMetadata._() {
     throw new UnsupportedError("Not supported");
@@ -21104,7 +21105,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaSession")
-class MediaSession extends Interceptor {
+class MediaSession extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaSession._() {
     throw new UnsupportedError("Not supported");
@@ -21133,7 +21134,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MediaSettingsRange")
-class MediaSettingsRange extends Interceptor {
+class MediaSettingsRange extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MediaSettingsRange._() {
     throw new UnsupportedError("Not supported");
@@ -21442,7 +21443,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MemoryInfo")
-class MemoryInfo extends Interceptor {
+class MemoryInfo extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MemoryInfo._() {
     throw new UnsupportedError("Not supported");
@@ -21500,7 +21501,7 @@
 
 @Unstable()
 @Native("MessageChannel")
-class MessageChannel extends Interceptor {
+class MessageChannel extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MessageChannel._() {
     throw new UnsupportedError("Not supported");
@@ -21713,7 +21714,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Metadata")
-class Metadata extends Interceptor {
+class Metadata extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Metadata._() {
     throw new UnsupportedError("Not supported");
@@ -21863,7 +21864,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MIDIInputMap")
-class MidiInputMap extends Interceptor with MapMixin<String, dynamic> {
+class MidiInputMap extends JavaScriptObject with MapMixin<String, dynamic> {
   // To suppress missing implicit constructor warnings.
   factory MidiInputMap._() {
     throw new UnsupportedError("Not supported");
@@ -21969,7 +21970,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MIDIOutputMap")
-class MidiOutputMap extends Interceptor with MapMixin<String, dynamic> {
+class MidiOutputMap extends JavaScriptObject with MapMixin<String, dynamic> {
   // To suppress missing implicit constructor warnings.
   factory MidiOutputMap._() {
     throw new UnsupportedError("Not supported");
@@ -22066,7 +22067,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MimeType")
-class MimeType extends Interceptor {
+class MimeType extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MimeType._() {
     throw new UnsupportedError("Not supported");
@@ -22085,7 +22086,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MimeTypeArray")
-class MimeTypeArray extends Interceptor
+class MimeTypeArray extends JavaScriptObject
     with ListMixin<MimeType>, ImmutableListMixin<MimeType>
     implements List<MimeType>, JavaScriptIndexingBehavior<MimeType> {
   // To suppress missing implicit constructor warnings.
@@ -22450,7 +22451,7 @@
 @SupportedBrowser(SupportedBrowser.FIREFOX)
 @SupportedBrowser(SupportedBrowser.SAFARI)
 @Native("MutationObserver,WebKitMutationObserver")
-class MutationObserver extends Interceptor {
+class MutationObserver extends JavaScriptObject {
   void disconnect() native;
 
   void _observe(Node target, [Map? options]) {
@@ -22555,7 +22556,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MutationRecord")
-class MutationRecord extends Interceptor {
+class MutationRecord extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory MutationRecord._() {
     throw new UnsupportedError("Not supported");
@@ -22588,7 +22589,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NavigationPreloadManager")
-class NavigationPreloadManager extends Interceptor {
+class NavigationPreloadManager extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NavigationPreloadManager._() {
     throw new UnsupportedError("Not supported");
@@ -22861,7 +22862,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NavigatorAutomationInformation")
-class NavigatorAutomationInformation extends Interceptor {
+class NavigatorAutomationInformation extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NavigatorAutomationInformation._() {
     throw new UnsupportedError("Not supported");
@@ -22874,7 +22875,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NavigatorConcurrentHardware")
-class NavigatorConcurrentHardware extends Interceptor {
+class NavigatorConcurrentHardware extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NavigatorConcurrentHardware._() {
     throw new UnsupportedError("Not supported");
@@ -22887,7 +22888,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NavigatorCookies")
-class NavigatorCookies extends Interceptor {
+class NavigatorCookies extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NavigatorCookies._() {
     throw new UnsupportedError("Not supported");
@@ -22899,7 +22900,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class NavigatorID extends Interceptor {
+abstract class NavigatorID extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NavigatorID._() {
     throw new UnsupportedError("Not supported");
@@ -22923,7 +22924,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class NavigatorLanguage extends Interceptor {
+abstract class NavigatorLanguage extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NavigatorLanguage._() {
     throw new UnsupportedError("Not supported");
@@ -22937,7 +22938,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class NavigatorOnLine extends Interceptor {
+abstract class NavigatorOnLine extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NavigatorOnLine._() {
     throw new UnsupportedError("Not supported");
@@ -22950,7 +22951,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NavigatorUserMediaError")
-class NavigatorUserMediaError extends Interceptor {
+class NavigatorUserMediaError extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NavigatorUserMediaError._() {
     throw new UnsupportedError("Not supported");
@@ -23546,7 +23547,7 @@
 
 @Unstable()
 @Native("NodeFilter")
-class NodeFilter extends Interceptor {
+class NodeFilter extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NodeFilter._() {
     throw new UnsupportedError("Not supported");
@@ -23580,7 +23581,7 @@
 
 @Unstable()
 @Native("NodeIterator")
-class NodeIterator extends Interceptor {
+class NodeIterator extends JavaScriptObject {
   factory NodeIterator(Node root, int whatToShow) {
     return document._createNodeIterator(root, whatToShow, null);
   }
@@ -23608,7 +23609,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NodeList,RadioNodeList")
-class NodeList extends Interceptor
+class NodeList extends JavaScriptObject
     with ListMixin<Node>, ImmutableListMixin<Node>
     implements List<Node>, JavaScriptIndexingBehavior<Node> {
   // To suppress missing implicit constructor warnings.
@@ -23669,7 +23670,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NonDocumentTypeChildNode")
-class NonDocumentTypeChildNode extends Interceptor {
+class NonDocumentTypeChildNode extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NonDocumentTypeChildNode._() {
     throw new UnsupportedError("Not supported");
@@ -23684,7 +23685,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NonElementParentNode")
-class NonElementParentNode extends Interceptor {
+class NonElementParentNode extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NonElementParentNode._() {
     throw new UnsupportedError("Not supported");
@@ -23697,7 +23698,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NoncedElement")
-class NoncedElement extends Interceptor {
+class NoncedElement extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory NoncedElement._() {
     throw new UnsupportedError("Not supported");
@@ -24038,7 +24039,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OffscreenCanvasRenderingContext2D")
-class OffscreenCanvasRenderingContext2D extends Interceptor
+class OffscreenCanvasRenderingContext2D extends JavaScriptObject
     implements _CanvasPath {
   // To suppress missing implicit constructor warnings.
   factory OffscreenCanvasRenderingContext2D._() {
@@ -24482,7 +24483,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OverconstrainedError")
-class OverconstrainedError extends Interceptor {
+class OverconstrainedError extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory OverconstrainedError._() {
     throw new UnsupportedError("Not supported");
@@ -24536,7 +24537,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PaintRenderingContext2D")
-class PaintRenderingContext2D extends Interceptor implements _CanvasPath {
+class PaintRenderingContext2D extends JavaScriptObject implements _CanvasPath {
   // To suppress missing implicit constructor warnings.
   factory PaintRenderingContext2D._() {
     throw new UnsupportedError("Not supported");
@@ -24693,7 +24694,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PaintSize")
-class PaintSize extends Interceptor {
+class PaintSize extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PaintSize._() {
     throw new UnsupportedError("Not supported");
@@ -24777,7 +24778,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class ParentNode extends Interceptor {
+abstract class ParentNode extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ParentNode._() {
     throw new UnsupportedError("Not supported");
@@ -24847,7 +24848,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Path2D")
-class Path2D extends Interceptor implements _CanvasPath {
+class Path2D extends JavaScriptObject implements _CanvasPath {
   // To suppress missing implicit constructor warnings.
   factory Path2D._() {
     throw new UnsupportedError("Not supported");
@@ -24901,7 +24902,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PaymentAddress")
-class PaymentAddress extends Interceptor {
+class PaymentAddress extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PaymentAddress._() {
     throw new UnsupportedError("Not supported");
@@ -24934,7 +24935,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PaymentInstruments")
-class PaymentInstruments extends Interceptor {
+class PaymentInstruments extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PaymentInstruments._() {
     throw new UnsupportedError("Not supported");
@@ -24965,7 +24966,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PaymentManager")
-class PaymentManager extends Interceptor {
+class PaymentManager extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PaymentManager._() {
     throw new UnsupportedError("Not supported");
@@ -25101,7 +25102,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PaymentResponse")
-class PaymentResponse extends Interceptor {
+class PaymentResponse extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PaymentResponse._() {
     throw new UnsupportedError("Not supported");
@@ -25177,7 +25178,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PerformanceEntry")
-class PerformanceEntry extends Interceptor {
+class PerformanceEntry extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PerformanceEntry._() {
     throw new UnsupportedError("Not supported");
@@ -25232,7 +25233,7 @@
 
 @Unstable()
 @Native("PerformanceNavigation")
-class PerformanceNavigation extends Interceptor {
+class PerformanceNavigation extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PerformanceNavigation._() {
     throw new UnsupportedError("Not supported");
@@ -25286,7 +25287,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PerformanceObserver")
-class PerformanceObserver extends Interceptor {
+class PerformanceObserver extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PerformanceObserver._() {
     throw new UnsupportedError("Not supported");
@@ -25323,7 +25324,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PerformanceObserverEntryList")
-class PerformanceObserverEntryList extends Interceptor {
+class PerformanceObserverEntryList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PerformanceObserverEntryList._() {
     throw new UnsupportedError("Not supported");
@@ -25399,7 +25400,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PerformanceServerTiming")
-class PerformanceServerTiming extends Interceptor {
+class PerformanceServerTiming extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PerformanceServerTiming._() {
     throw new UnsupportedError("Not supported");
@@ -25417,7 +25418,7 @@
 
 @Unstable()
 @Native("PerformanceTiming")
-class PerformanceTiming extends Interceptor {
+class PerformanceTiming extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PerformanceTiming._() {
     throw new UnsupportedError("Not supported");
@@ -25488,7 +25489,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Permissions")
-class Permissions extends Interceptor {
+class Permissions extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Permissions._() {
     throw new UnsupportedError("Not supported");
@@ -25521,7 +25522,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PhotoCapabilities")
-class PhotoCapabilities extends Interceptor {
+class PhotoCapabilities extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PhotoCapabilities._() {
     throw new UnsupportedError("Not supported");
@@ -25557,7 +25558,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Plugin")
-class Plugin extends Interceptor {
+class Plugin extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Plugin._() {
     throw new UnsupportedError("Not supported");
@@ -25580,7 +25581,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PluginArray")
-class PluginArray extends Interceptor
+class PluginArray extends JavaScriptObject
     with ListMixin<Plugin>, ImmutableListMixin<Plugin>
     implements List<Plugin>, JavaScriptIndexingBehavior<Plugin> {
   // To suppress missing implicit constructor warnings.
@@ -25745,7 +25746,7 @@
 
 @Unstable()
 @Native("PositionError,GeolocationPositionError")
-class PositionError extends Interceptor {
+class PositionError extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PositionError._() {
     throw new UnsupportedError("Not supported");
@@ -25797,7 +25798,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Presentation")
-class Presentation extends Interceptor {
+class Presentation extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Presentation._() {
     throw new UnsupportedError("Not supported");
@@ -25924,7 +25925,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PresentationReceiver")
-class PresentationReceiver extends Interceptor {
+class PresentationReceiver extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PresentationReceiver._() {
     throw new UnsupportedError("Not supported");
@@ -26128,7 +26129,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PushManager")
-class PushManager extends Interceptor {
+class PushManager extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PushManager._() {
     throw new UnsupportedError("Not supported");
@@ -26162,7 +26163,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PushMessageData")
-class PushMessageData extends Interceptor {
+class PushMessageData extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PushMessageData._() {
     throw new UnsupportedError("Not supported");
@@ -26181,7 +26182,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PushSubscription")
-class PushSubscription extends Interceptor {
+class PushSubscription extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PushSubscription._() {
     throw new UnsupportedError("Not supported");
@@ -26203,7 +26204,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PushSubscriptionOptions")
-class PushSubscriptionOptions extends Interceptor {
+class PushSubscriptionOptions extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PushSubscriptionOptions._() {
     throw new UnsupportedError("Not supported");
@@ -26269,7 +26270,7 @@
 
 @Unstable()
 @Native("Range")
-class Range extends Interceptor {
+class Range extends JavaScriptObject {
   factory Range() => document.createRange();
 
   factory Range.fromPoint(Point point) =>
@@ -26377,7 +26378,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("RelatedApplication")
-class RelatedApplication extends Interceptor {
+class RelatedApplication extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory RelatedApplication._() {
     throw new UnsupportedError("Not supported");
@@ -26447,7 +26448,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ReportBody")
-class ReportBody extends Interceptor {
+class ReportBody extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ReportBody._() {
     throw new UnsupportedError("Not supported");
@@ -26458,7 +26459,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ReportingObserver")
-class ReportingObserver extends Interceptor {
+class ReportingObserver extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ReportingObserver._() {
     throw new UnsupportedError("Not supported");
@@ -26495,7 +26496,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ResizeObserver")
-class ResizeObserver extends Interceptor {
+class ResizeObserver extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ResizeObserver._() {
     throw new UnsupportedError("Not supported");
@@ -26526,7 +26527,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ResizeObserverEntry")
-class ResizeObserverEntry extends Interceptor {
+class ResizeObserverEntry extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ResizeObserverEntry._() {
     throw new UnsupportedError("Not supported");
@@ -26541,7 +26542,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("RTCCertificate")
-class RtcCertificate extends Interceptor {
+class RtcCertificate extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory RtcCertificate._() {
     throw new UnsupportedError("Not supported");
@@ -26744,7 +26745,7 @@
 
 @SupportedBrowser(SupportedBrowser.CHROME)
 @Native("RTCIceCandidate,mozRTCIceCandidate")
-class RtcIceCandidate extends Interceptor {
+class RtcIceCandidate extends JavaScriptObject {
   factory RtcIceCandidate(Map dictionary) {
     var constructorName = JS('', 'window[#]', 'RTCIceCandidate');
     return JS('RtcIceCandidate', 'new #(#)', constructorName,
@@ -26772,7 +26773,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("RTCLegacyStatsReport")
-class RtcLegacyStatsReport extends Interceptor {
+class RtcLegacyStatsReport extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory RtcLegacyStatsReport._() {
     throw new UnsupportedError("Not supported");
@@ -27106,7 +27107,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("RTCRtpContributingSource")
-class RtcRtpContributingSource extends Interceptor {
+class RtcRtpContributingSource extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory RtcRtpContributingSource._() {
     throw new UnsupportedError("Not supported");
@@ -27121,7 +27122,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("RTCRtpReceiver")
-class RtcRtpReceiver extends Interceptor {
+class RtcRtpReceiver extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory RtcRtpReceiver._() {
     throw new UnsupportedError("Not supported");
@@ -27136,7 +27137,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("RTCRtpSender")
-class RtcRtpSender extends Interceptor {
+class RtcRtpSender extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory RtcRtpSender._() {
     throw new UnsupportedError("Not supported");
@@ -27150,7 +27151,7 @@
 
 @SupportedBrowser(SupportedBrowser.CHROME)
 @Native("RTCSessionDescription,mozRTCSessionDescription")
-class RtcSessionDescription extends Interceptor {
+class RtcSessionDescription extends JavaScriptObject {
   factory RtcSessionDescription(Map dictionary) {
     var constructorName = JS('', 'window[#]', 'RTCSessionDescription');
     return JS('RtcSessionDescription', 'new #(#)', constructorName,
@@ -27174,7 +27175,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("RTCStatsReport")
-class RtcStatsReport extends Interceptor with MapMixin<String, dynamic> {
+class RtcStatsReport extends JavaScriptObject with MapMixin<String, dynamic> {
   // To suppress missing implicit constructor warnings.
   factory RtcStatsReport._() {
     throw new UnsupportedError("Not supported");
@@ -27242,7 +27243,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("RTCStatsResponse")
-class RtcStatsResponse extends Interceptor {
+class RtcStatsResponse extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory RtcStatsResponse._() {
     throw new UnsupportedError("Not supported");
@@ -27281,7 +27282,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Screen")
-class Screen extends Interceptor {
+class Screen extends JavaScriptObject {
   Rectangle get available =>
       new Rectangle(_availLeft!, _availTop!, _availWidth!, _availHeight!);
   // To suppress missing implicit constructor warnings.
@@ -27400,7 +27401,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ScrollState")
-class ScrollState extends Interceptor {
+class ScrollState extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ScrollState._() {
     throw new UnsupportedError("Not supported");
@@ -27645,7 +27646,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Selection")
-class Selection extends Interceptor {
+class Selection extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Selection._() {
     throw new UnsupportedError("Not supported");
@@ -28050,7 +28051,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SharedArrayBuffer")
-class SharedArrayBuffer extends Interceptor {
+class SharedArrayBuffer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SharedArrayBuffer._() {
     throw new UnsupportedError("Not supported");
@@ -28370,7 +28371,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SpeechGrammar")
-class SpeechGrammar extends Interceptor {
+class SpeechGrammar extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SpeechGrammar._() {
     throw new UnsupportedError("Not supported");
@@ -28395,7 +28396,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SpeechGrammarList")
-class SpeechGrammarList extends Interceptor
+class SpeechGrammarList extends JavaScriptObject
     with ListMixin<SpeechGrammar>, ImmutableListMixin<SpeechGrammar>
     implements List<SpeechGrammar>, JavaScriptIndexingBehavior<SpeechGrammar> {
   // To suppress missing implicit constructor warnings.
@@ -28649,7 +28650,7 @@
 
 @SupportedBrowser(SupportedBrowser.CHROME, '25')
 @Native("SpeechRecognitionAlternative")
-class SpeechRecognitionAlternative extends Interceptor {
+class SpeechRecognitionAlternative extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SpeechRecognitionAlternative._() {
     throw new UnsupportedError("Not supported");
@@ -28733,7 +28734,7 @@
 
 @SupportedBrowser(SupportedBrowser.CHROME, '25')
 @Native("SpeechRecognitionResult")
-class SpeechRecognitionResult extends Interceptor {
+class SpeechRecognitionResult extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SpeechRecognitionResult._() {
     throw new UnsupportedError("Not supported");
@@ -28933,7 +28934,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SpeechSynthesisVoice")
-class SpeechSynthesisVoice extends Interceptor {
+class SpeechSynthesisVoice extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SpeechSynthesisVoice._() {
     throw new UnsupportedError("Not supported");
@@ -28956,7 +28957,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("StaticRange")
-class StaticRange extends Interceptor {
+class StaticRange extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory StaticRange._() {
     throw new UnsupportedError("Not supported");
@@ -28998,7 +28999,7 @@
  */
 @Unstable()
 @Native("Storage")
-class Storage extends Interceptor with MapMixin<String, String> {
+class Storage extends JavaScriptObject with MapMixin<String, String> {
   void addAll(Map<String, String> other) {
     other.forEach((k, v) {
       this[k] = v;
@@ -29146,7 +29147,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("StorageManager")
-class StorageManager extends Interceptor {
+class StorageManager extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory StorageManager._() {
     throw new UnsupportedError("Not supported");
@@ -29217,7 +29218,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("StyleMedia")
-class StyleMedia extends Interceptor {
+class StyleMedia extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory StyleMedia._() {
     throw new UnsupportedError("Not supported");
@@ -29249,7 +29250,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("StylePropertyMapReadonly")
-class StylePropertyMapReadonly extends Interceptor {
+class StylePropertyMapReadonly extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory StylePropertyMapReadonly._() {
     throw new UnsupportedError("Not supported");
@@ -29268,7 +29269,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("StyleSheet")
-class StyleSheet extends Interceptor {
+class StyleSheet extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory StyleSheet._() {
     throw new UnsupportedError("Not supported");
@@ -29317,7 +29318,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SyncManager")
-class SyncManager extends Interceptor {
+class SyncManager extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SyncManager._() {
     throw new UnsupportedError("Not supported");
@@ -29867,7 +29868,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TextDetector")
-class TextDetector extends Interceptor {
+class TextDetector extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TextDetector._() {
     throw new UnsupportedError("Not supported");
@@ -29918,7 +29919,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TextMetrics")
-class TextMetrics extends Interceptor {
+class TextMetrics extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TextMetrics._() {
     throw new UnsupportedError("Not supported");
@@ -30049,7 +30050,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TextTrackCueList")
-class TextTrackCueList extends Interceptor
+class TextTrackCueList extends JavaScriptObject
     with ListMixin<TextTrackCue>, ImmutableListMixin<TextTrackCue>
     implements List<TextTrackCue>, JavaScriptIndexingBehavior<TextTrackCue> {
   // To suppress missing implicit constructor warnings.
@@ -30212,7 +30213,7 @@
 
 @Unstable()
 @Native("TimeRanges")
-class TimeRanges extends Interceptor {
+class TimeRanges extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TimeRanges._() {
     throw new UnsupportedError("Not supported");
@@ -30259,7 +30260,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Touch")
-class Touch extends Interceptor {
+class Touch extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Touch._() {
     throw new UnsupportedError("Not supported");
@@ -30389,7 +30390,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TouchList")
-class TouchList extends Interceptor
+class TouchList extends JavaScriptObject
     with ListMixin<Touch>, ImmutableListMixin<Touch>
     implements List<Touch>, JavaScriptIndexingBehavior<Touch> {
   // To suppress missing implicit constructor warnings.
@@ -30452,7 +30453,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TrackDefault")
-class TrackDefault extends Interceptor {
+class TrackDefault extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TrackDefault._() {
     throw new UnsupportedError("Not supported");
@@ -30496,7 +30497,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TrackDefaultList")
-class TrackDefaultList extends Interceptor {
+class TrackDefaultList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TrackDefaultList._() {
     throw new UnsupportedError("Not supported");
@@ -30638,7 +30639,7 @@
 
 @Unstable()
 @Native("TreeWalker")
-class TreeWalker extends Interceptor {
+class TreeWalker extends JavaScriptObject {
   factory TreeWalker(Node root, int whatToShow) {
     return document._createTreeWalker(root, whatToShow, null);
   }
@@ -30676,7 +30677,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TrustedHTML")
-class TrustedHtml extends Interceptor {
+class TrustedHtml extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TrustedHtml._() {
     throw new UnsupportedError("Not supported");
@@ -30691,7 +30692,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TrustedScriptURL")
-class TrustedScriptUrl extends Interceptor {
+class TrustedScriptUrl extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TrustedScriptUrl._() {
     throw new UnsupportedError("Not supported");
@@ -30704,7 +30705,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("TrustedURL")
-class TrustedUrl extends Interceptor {
+class TrustedUrl extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TrustedUrl._() {
     throw new UnsupportedError("Not supported");
@@ -30798,7 +30799,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("UnderlyingSourceBase")
-class UnderlyingSourceBase extends Interceptor {
+class UnderlyingSourceBase extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory UnderlyingSourceBase._() {
     throw new UnsupportedError("Not supported");
@@ -30838,7 +30839,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("URL")
-class Url extends Interceptor {
+class Url extends JavaScriptObject {
   static String createObjectUrl(blob_OR_source_OR_stream) => JS(
       'String',
       '(self.URL || self.webkitURL).createObjectURL(#)',
@@ -30912,7 +30913,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("URLSearchParams")
-class UrlSearchParams extends Interceptor {
+class UrlSearchParams extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory UrlSearchParams._() {
     throw new UnsupportedError("Not supported");
@@ -30947,7 +30948,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class UrlUtilsReadOnly extends Interceptor {
+abstract class UrlUtilsReadOnly extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory UrlUtilsReadOnly._() {
     throw new UnsupportedError("Not supported");
@@ -30989,7 +30990,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VRCoordinateSystem")
-class VRCoordinateSystem extends Interceptor {
+class VRCoordinateSystem extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VRCoordinateSystem._() {
     throw new UnsupportedError("Not supported");
@@ -31099,7 +31100,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VRDisplayCapabilities")
-class VRDisplayCapabilities extends Interceptor {
+class VRDisplayCapabilities extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VRDisplayCapabilities._() {
     throw new UnsupportedError("Not supported");
@@ -31145,7 +31146,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VREyeParameters")
-class VREyeParameters extends Interceptor {
+class VREyeParameters extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VREyeParameters._() {
     throw new UnsupportedError("Not supported");
@@ -31162,7 +31163,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VRFrameData")
-class VRFrameData extends Interceptor {
+class VRFrameData extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VRFrameData._() {
     throw new UnsupportedError("Not supported");
@@ -31203,7 +31204,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VRPose")
-class VRPose extends Interceptor {
+class VRPose extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VRPose._() {
     throw new UnsupportedError("Not supported");
@@ -31290,7 +31291,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VRStageBounds")
-class VRStageBounds extends Interceptor {
+class VRStageBounds extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VRStageBounds._() {
     throw new UnsupportedError("Not supported");
@@ -31303,7 +31304,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VRStageBoundsPoint")
-class VRStageBoundsPoint extends Interceptor {
+class VRStageBoundsPoint extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VRStageBoundsPoint._() {
     throw new UnsupportedError("Not supported");
@@ -31318,7 +31319,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VRStageParameters")
-class VRStageParameters extends Interceptor {
+class VRStageParameters extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VRStageParameters._() {
     throw new UnsupportedError("Not supported");
@@ -31335,7 +31336,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ValidityState")
-class ValidityState extends Interceptor {
+class ValidityState extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ValidityState._() {
     throw new UnsupportedError("Not supported");
@@ -31429,7 +31430,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VideoPlaybackQuality")
-class VideoPlaybackQuality extends Interceptor {
+class VideoPlaybackQuality extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VideoPlaybackQuality._() {
     throw new UnsupportedError("Not supported");
@@ -31448,7 +31449,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VideoTrack")
-class VideoTrack extends Interceptor {
+class VideoTrack extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VideoTrack._() {
     throw new UnsupportedError("Not supported");
@@ -31595,7 +31596,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("VTTRegion")
-class VttRegion extends Interceptor {
+class VttRegion extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VttRegion._() {
     throw new UnsupportedError("Not supported");
@@ -33756,7 +33757,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class WindowBase64 extends Interceptor {
+abstract class WindowBase64 extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory WindowBase64._() {
     throw new UnsupportedError("Not supported");
@@ -34026,7 +34027,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WorkletAnimation")
-class WorkletAnimation extends Interceptor {
+class WorkletAnimation extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory WorkletAnimation._() {
     throw new UnsupportedError("Not supported");
@@ -34057,7 +34058,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WorkletGlobalScope")
-class WorkletGlobalScope extends Interceptor {
+class WorkletGlobalScope extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory WorkletGlobalScope._() {
     throw new UnsupportedError("Not supported");
@@ -34070,7 +34071,7 @@
 // http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator
 @deprecated // experimental
 @Native("XPathEvaluator")
-class XPathEvaluator extends Interceptor {
+class XPathEvaluator extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory XPathEvaluator._() {
     throw new UnsupportedError("Not supported");
@@ -34098,7 +34099,7 @@
 // http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathExpression
 @deprecated // experimental
 @Native("XPathExpression")
-class XPathExpression extends Interceptor {
+class XPathExpression extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory XPathExpression._() {
     throw new UnsupportedError("Not supported");
@@ -34113,7 +34114,7 @@
 // http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathNSResolver
 @deprecated // experimental
 @Native("XPathNSResolver")
-class XPathNSResolver extends Interceptor {
+class XPathNSResolver extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory XPathNSResolver._() {
     throw new UnsupportedError("Not supported");
@@ -34129,7 +34130,7 @@
 // http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathResult
 @deprecated // experimental
 @Native("XPathResult")
-class XPathResult extends Interceptor {
+class XPathResult extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory XPathResult._() {
     throw new UnsupportedError("Not supported");
@@ -34191,7 +34192,7 @@
 // http://domparsing.spec.whatwg.org/#the-xmlserializer-interface
 @deprecated // stable
 @Native("XMLSerializer")
-class XmlSerializer extends Interceptor {
+class XmlSerializer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory XmlSerializer._() {
     throw new UnsupportedError("Not supported");
@@ -34214,7 +34215,7 @@
 @SupportedBrowser(SupportedBrowser.SAFARI)
 @deprecated // nonstandard
 @Native("XSLTProcessor")
-class XsltProcessor extends Interceptor {
+class XsltProcessor extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory XsltProcessor._() {
     throw new UnsupportedError("Not supported");
@@ -34274,7 +34275,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Bluetooth")
-abstract class _Bluetooth extends Interceptor {
+abstract class _Bluetooth extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _Bluetooth._() {
     throw new UnsupportedError("Not supported");
@@ -34285,7 +34286,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BluetoothCharacteristicProperties")
-abstract class _BluetoothCharacteristicProperties extends Interceptor {
+abstract class _BluetoothCharacteristicProperties extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _BluetoothCharacteristicProperties._() {
     throw new UnsupportedError("Not supported");
@@ -34318,7 +34319,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BluetoothRemoteGATTServer")
-abstract class _BluetoothRemoteGATTServer extends Interceptor {
+abstract class _BluetoothRemoteGATTServer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _BluetoothRemoteGATTServer._() {
     throw new UnsupportedError("Not supported");
@@ -34329,7 +34330,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BluetoothRemoteGATTService")
-abstract class _BluetoothRemoteGATTService extends Interceptor {
+abstract class _BluetoothRemoteGATTService extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _BluetoothRemoteGATTService._() {
     throw new UnsupportedError("Not supported");
@@ -34340,7 +34341,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BluetoothUUID")
-abstract class _BluetoothUUID extends Interceptor {
+abstract class _BluetoothUUID extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _BluetoothUUID._() {
     throw new UnsupportedError("Not supported");
@@ -34351,7 +34352,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("BudgetService")
-class _BudgetService extends Interceptor {
+class _BudgetService extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _BudgetService._() {
     throw new UnsupportedError("Not supported");
@@ -34371,7 +34372,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Cache")
-abstract class _Cache extends Interceptor {
+abstract class _Cache extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _Cache._() {
     throw new UnsupportedError("Not supported");
@@ -34381,7 +34382,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class _CanvasPath extends Interceptor {
+abstract class _CanvasPath extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _CanvasPath._() {
     throw new UnsupportedError("Not supported");
@@ -34415,7 +34416,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("CSSRuleList")
-class _CssRuleList extends Interceptor
+class _CssRuleList extends JavaScriptObject
     with ListMixin<CssRule>, ImmutableListMixin<CssRule>
     implements List<CssRule>, JavaScriptIndexingBehavior<CssRule> {
   // To suppress missing implicit constructor warnings.
@@ -34476,7 +34477,7 @@
 
 @SupportedBrowser(SupportedBrowser.CHROME)
 @Native("DOMFileSystemSync")
-abstract class _DOMFileSystemSync extends Interceptor {
+abstract class _DOMFileSystemSync extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _DOMFileSystemSync._() {
     throw new UnsupportedError("Not supported");
@@ -34498,7 +34499,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("DirectoryReaderSync")
-abstract class _DirectoryReaderSync extends Interceptor {
+abstract class _DirectoryReaderSync extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _DirectoryReaderSync._() {
     throw new UnsupportedError("Not supported");
@@ -34683,7 +34684,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EntrySync")
-abstract class _EntrySync extends Interceptor {
+abstract class _EntrySync extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _EntrySync._() {
     throw new UnsupportedError("Not supported");
@@ -34705,7 +34706,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("FileReaderSync")
-abstract class _FileReaderSync extends Interceptor {
+abstract class _FileReaderSync extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _FileReaderSync._() {
     throw new UnsupportedError("Not supported");
@@ -34722,7 +34723,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("FileWriterSync")
-abstract class _FileWriterSync extends Interceptor {
+abstract class _FileWriterSync extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _FileWriterSync._() {
     throw new UnsupportedError("Not supported");
@@ -34733,7 +34734,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("GamepadList")
-class _GamepadList extends Interceptor
+class _GamepadList extends JavaScriptObject
     with ListMixin<Gamepad?>, ImmutableListMixin<Gamepad?>
     implements List<Gamepad?>, JavaScriptIndexingBehavior<Gamepad?> {
   // To suppress missing implicit constructor warnings.
@@ -34795,7 +34796,7 @@
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#dom-document-all
 @deprecated // deprecated
 @Native("HTMLAllCollection")
-abstract class _HTMLAllCollection extends Interceptor {
+abstract class _HTMLAllCollection extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _HTMLAllCollection._() {
     throw new UnsupportedError("Not supported");
@@ -34906,7 +34907,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Mojo")
-abstract class _Mojo extends Interceptor {
+abstract class _Mojo extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _Mojo._() {
     throw new UnsupportedError("Not supported");
@@ -34917,7 +34918,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MojoHandle")
-abstract class _MojoHandle extends Interceptor {
+abstract class _MojoHandle extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _MojoHandle._() {
     throw new UnsupportedError("Not supported");
@@ -34981,7 +34982,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("MojoWatcher")
-abstract class _MojoWatcher extends Interceptor {
+abstract class _MojoWatcher extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _MojoWatcher._() {
     throw new UnsupportedError("Not supported");
@@ -34992,7 +34993,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("NFC")
-abstract class _NFC extends Interceptor {
+abstract class _NFC extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _NFC._() {
     throw new UnsupportedError("Not supported");
@@ -35005,7 +35006,7 @@
 // http://dom.spec.whatwg.org/#namednodemap
 @deprecated // deprecated
 @Native("NamedNodeMap,MozNamedAttrMap")
-class _NamedNodeMap extends Interceptor
+class _NamedNodeMap extends JavaScriptObject
     with ListMixin<Node>, ImmutableListMixin<Node>
     implements List<Node>, JavaScriptIndexingBehavior<Node> {
   // To suppress missing implicit constructor warnings.
@@ -35078,7 +35079,7 @@
 
 @deprecated // nonstandard
 @Native("PagePopupController")
-abstract class _PagePopupController extends Interceptor {
+abstract class _PagePopupController extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _PagePopupController._() {
     throw new UnsupportedError("Not supported");
@@ -35097,7 +35098,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Report")
-class _Report extends Interceptor {
+class _Report extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _Report._() {
     throw new UnsupportedError("Not supported");
@@ -35195,7 +35196,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SpeechRecognitionResultList")
-class _SpeechRecognitionResultList extends Interceptor
+class _SpeechRecognitionResultList extends JavaScriptObject
     with
         ListMixin<SpeechRecognitionResult>,
         ImmutableListMixin<SpeechRecognitionResult>
@@ -35259,7 +35260,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("StyleSheetList")
-class _StyleSheetList extends Interceptor
+class _StyleSheetList extends JavaScriptObject
     with ListMixin<StyleSheet>, ImmutableListMixin<StyleSheet>
     implements List<StyleSheet>, JavaScriptIndexingBehavior<StyleSheet> {
   // To suppress missing implicit constructor warnings.
@@ -35321,7 +35322,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SubtleCrypto")
-abstract class _SubtleCrypto extends Interceptor {
+abstract class _SubtleCrypto extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _SubtleCrypto._() {
     throw new UnsupportedError("Not supported");
@@ -35343,7 +35344,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBAlternateInterface")
-abstract class _USBAlternateInterface extends Interceptor {
+abstract class _USBAlternateInterface extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBAlternateInterface._() {
     throw new UnsupportedError("Not supported");
@@ -35362,7 +35363,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBConfiguration")
-abstract class _USBConfiguration extends Interceptor {
+abstract class _USBConfiguration extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBConfiguration._() {
     throw new UnsupportedError("Not supported");
@@ -35403,7 +35404,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBDevice")
-abstract class _USBDevice extends Interceptor {
+abstract class _USBDevice extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBDevice._() {
     throw new UnsupportedError("Not supported");
@@ -35414,7 +35415,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBEndpoint")
-abstract class _USBEndpoint extends Interceptor {
+abstract class _USBEndpoint extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBEndpoint._() {
     throw new UnsupportedError("Not supported");
@@ -35436,7 +35437,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBInTransferResult")
-abstract class _USBInTransferResult extends Interceptor {
+abstract class _USBInTransferResult extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBInTransferResult._() {
     throw new UnsupportedError("Not supported");
@@ -35458,7 +35459,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBInterface")
-abstract class _USBInterface extends Interceptor {
+abstract class _USBInterface extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBInterface._() {
     throw new UnsupportedError("Not supported");
@@ -35475,7 +35476,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBIsochronousInTransferPacket")
-abstract class _USBIsochronousInTransferPacket extends Interceptor {
+abstract class _USBIsochronousInTransferPacket extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBIsochronousInTransferPacket._() {
     throw new UnsupportedError("Not supported");
@@ -35502,7 +35503,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBIsochronousInTransferResult")
-abstract class _USBIsochronousInTransferResult extends Interceptor {
+abstract class _USBIsochronousInTransferResult extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBIsochronousInTransferResult._() {
     throw new UnsupportedError("Not supported");
@@ -35531,7 +35532,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBIsochronousOutTransferPacket")
-abstract class _USBIsochronousOutTransferPacket extends Interceptor {
+abstract class _USBIsochronousOutTransferPacket extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBIsochronousOutTransferPacket._() {
     throw new UnsupportedError("Not supported");
@@ -35558,7 +35559,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBIsochronousOutTransferResult")
-abstract class _USBIsochronousOutTransferResult extends Interceptor {
+abstract class _USBIsochronousOutTransferResult extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBIsochronousOutTransferResult._() {
     throw new UnsupportedError("Not supported");
@@ -35578,7 +35579,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("USBOutTransferResult")
-abstract class _USBOutTransferResult extends Interceptor {
+abstract class _USBOutTransferResult extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _USBOutTransferResult._() {
     throw new UnsupportedError("Not supported");
@@ -35602,7 +35603,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class _WindowTimers extends Interceptor {
+abstract class _WindowTimers extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _WindowTimers._() {
     throw new UnsupportedError("Not supported");
@@ -35625,7 +35626,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WorkerLocation")
-abstract class _WorkerLocation extends Interceptor implements UrlUtilsReadOnly {
+abstract class _WorkerLocation extends JavaScriptObject
+    implements UrlUtilsReadOnly {
   // To suppress missing implicit constructor warnings.
   factory _WorkerLocation._() {
     throw new UnsupportedError("Not supported");
@@ -35658,7 +35660,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("Worklet")
-abstract class _Worklet extends Interceptor {
+abstract class _Worklet extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _Worklet._() {
     throw new UnsupportedError("Not supported");
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index ad56eea..e26356c 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -75,7 +75,7 @@
 import 'dart:typed_data';
 import 'dart:_js_helper' show Creates, Returns, JSName, Native;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+import 'dart:_interceptors' show JavaScriptObject, JSExtendableArray;
 import 'dart:_js_helper' show convertDartClosureToJS;
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
@@ -205,7 +205,7 @@
 
 @Unstable()
 @Native("IDBCursor")
-class Cursor extends Interceptor {
+class Cursor extends JavaScriptObject {
   Future delete() {
     try {
       return _completeRequest(_delete());
@@ -448,7 +448,7 @@
 @SupportedBrowser(SupportedBrowser.IE, '10')
 @Unstable()
 @Native("IDBFactory")
-class IdbFactory extends Interceptor {
+class IdbFactory extends JavaScriptObject {
   /**
    * Checks to see if Indexed DB is supported on the current platform.
    */
@@ -554,7 +554,7 @@
 
 @Unstable()
 @Native("IDBIndex")
-class Index extends Interceptor {
+class Index extends JavaScriptObject {
   Future<int> count([key_OR_range]) {
     try {
       var request = _count(key_OR_range);
@@ -696,7 +696,7 @@
 
 @Unstable()
 @Native("IDBKeyRange")
-class KeyRange extends Interceptor {
+class KeyRange extends JavaScriptObject {
   factory KeyRange.only(/*Key*/ value) =>
       _KeyRangeFactoryProvider.createKeyRange_only(value);
 
@@ -747,7 +747,7 @@
 
 @Unstable()
 @Native("IDBObjectStore")
-class ObjectStore extends Interceptor {
+class ObjectStore extends JavaScriptObject {
   Future add(value, [key]) {
     try {
       var request;
@@ -1012,7 +1012,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("IDBObservation")
-class Observation extends Interceptor {
+class Observation extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Observation._() {
     throw new UnsupportedError("Not supported");
@@ -1029,7 +1029,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("IDBObserver")
-class Observer extends Interceptor {
+class Observer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Observer._() {
     throw new UnsupportedError("Not supported");
@@ -1058,7 +1058,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("IDBObserverChanges")
-class ObserverChanges extends Interceptor {
+class ObserverChanges extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ObserverChanges._() {
     throw new UnsupportedError("Not supported");
diff --git a/sdk/lib/js/_js_annotations.dart b/sdk/lib/js/_js_annotations.dart
index b110632..2e24deb 100644
--- a/sdk/lib/js/_js_annotations.dart
+++ b/sdk/lib/js/_js_annotations.dart
@@ -18,10 +18,10 @@
   const _Anonymous();
 }
 
-// class _StaticInterop {
-//   const _StaticInterop();
-// }
+class _StaticInterop {
+  const _StaticInterop();
+}
 
 const _Anonymous anonymous = _Anonymous();
 
-// const _StaticInterop staticInterop = _StaticInterop();
+const _StaticInterop staticInterop = _StaticInterop();
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index aa97d19..9b2e992 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -17,7 +17,7 @@
 import 'dart:html_common';
 import 'dart:_js_helper' show Creates, Returns, JSName, Native;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor;
+import 'dart:_interceptors' show JavaScriptObject;
 // DO NOT EDIT - unless you are editing documentation as per:
 // https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:svg library.
@@ -66,7 +66,7 @@
 
 @Unstable()
 @Native("SVGAngle")
-class Angle extends Interceptor {
+class Angle extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Angle._() {
     throw new UnsupportedError("Not supported");
@@ -196,7 +196,7 @@
 
 @Unstable()
 @Native("SVGAnimatedAngle")
-class AnimatedAngle extends Interceptor {
+class AnimatedAngle extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedAngle._() {
     throw new UnsupportedError("Not supported");
@@ -212,7 +212,7 @@
 
 @Unstable()
 @Native("SVGAnimatedBoolean")
-class AnimatedBoolean extends Interceptor {
+class AnimatedBoolean extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedBoolean._() {
     throw new UnsupportedError("Not supported");
@@ -230,7 +230,7 @@
 
 @Unstable()
 @Native("SVGAnimatedEnumeration")
-class AnimatedEnumeration extends Interceptor {
+class AnimatedEnumeration extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedEnumeration._() {
     throw new UnsupportedError("Not supported");
@@ -248,7 +248,7 @@
 
 @Unstable()
 @Native("SVGAnimatedInteger")
-class AnimatedInteger extends Interceptor {
+class AnimatedInteger extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedInteger._() {
     throw new UnsupportedError("Not supported");
@@ -266,7 +266,7 @@
 
 @Unstable()
 @Native("SVGAnimatedLength")
-class AnimatedLength extends Interceptor {
+class AnimatedLength extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedLength._() {
     throw new UnsupportedError("Not supported");
@@ -282,7 +282,7 @@
 
 @Unstable()
 @Native("SVGAnimatedLengthList")
-class AnimatedLengthList extends Interceptor {
+class AnimatedLengthList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedLengthList._() {
     throw new UnsupportedError("Not supported");
@@ -298,7 +298,7 @@
 
 @Unstable()
 @Native("SVGAnimatedNumber")
-class AnimatedNumber extends Interceptor {
+class AnimatedNumber extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedNumber._() {
     throw new UnsupportedError("Not supported");
@@ -316,7 +316,7 @@
 
 @Unstable()
 @Native("SVGAnimatedNumberList")
-class AnimatedNumberList extends Interceptor {
+class AnimatedNumberList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedNumberList._() {
     throw new UnsupportedError("Not supported");
@@ -332,7 +332,7 @@
 
 @Unstable()
 @Native("SVGAnimatedPreserveAspectRatio")
-class AnimatedPreserveAspectRatio extends Interceptor {
+class AnimatedPreserveAspectRatio extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedPreserveAspectRatio._() {
     throw new UnsupportedError("Not supported");
@@ -348,7 +348,7 @@
 
 @Unstable()
 @Native("SVGAnimatedRect")
-class AnimatedRect extends Interceptor {
+class AnimatedRect extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedRect._() {
     throw new UnsupportedError("Not supported");
@@ -364,7 +364,7 @@
 
 @Unstable()
 @Native("SVGAnimatedString")
-class AnimatedString extends Interceptor {
+class AnimatedString extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedString._() {
     throw new UnsupportedError("Not supported");
@@ -382,7 +382,7 @@
 
 @Unstable()
 @Native("SVGAnimatedTransformList")
-class AnimatedTransformList extends Interceptor {
+class AnimatedTransformList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AnimatedTransformList._() {
     throw new UnsupportedError("Not supported");
@@ -1785,7 +1785,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Unstable()
-abstract class FilterPrimitiveStandardAttributes extends Interceptor {
+abstract class FilterPrimitiveStandardAttributes extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory FilterPrimitiveStandardAttributes._() {
     throw new UnsupportedError("Not supported");
@@ -1806,7 +1806,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Unstable()
-abstract class FitToViewBox extends Interceptor {
+abstract class FitToViewBox extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory FitToViewBox._() {
     throw new UnsupportedError("Not supported");
@@ -1986,7 +1986,7 @@
 
 @Unstable()
 @Native("SVGLength")
-class Length extends Interceptor {
+class Length extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Length._() {
     throw new UnsupportedError("Not supported");
@@ -2038,7 +2038,7 @@
 
 @Unstable()
 @Native("SVGLengthList")
-class LengthList extends Interceptor
+class LengthList extends JavaScriptObject
     with ListMixin<Length>, ImmutableListMixin<Length>
     implements List<Length> {
   // To suppress missing implicit constructor warnings.
@@ -2271,7 +2271,7 @@
 
 @Unstable()
 @Native("SVGMatrix")
-class Matrix extends Interceptor {
+class Matrix extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Matrix._() {
     throw new UnsupportedError("Not supported");
@@ -2347,7 +2347,7 @@
 
 @Unstable()
 @Native("SVGNumber")
-class Number extends Interceptor {
+class Number extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Number._() {
     throw new UnsupportedError("Not supported");
@@ -2363,7 +2363,7 @@
 
 @Unstable()
 @Native("SVGNumberList")
-class NumberList extends Interceptor
+class NumberList extends JavaScriptObject
     with ListMixin<Number>, ImmutableListMixin<Number>
     implements List<Number> {
   // To suppress missing implicit constructor warnings.
@@ -2514,7 +2514,7 @@
 
 @Unstable()
 @Native("SVGPoint")
-class Point extends Interceptor {
+class Point extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Point._() {
     throw new UnsupportedError("Not supported");
@@ -2536,7 +2536,7 @@
 
 @Unstable()
 @Native("SVGPointList")
-class PointList extends Interceptor {
+class PointList extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PointList._() {
     throw new UnsupportedError("Not supported");
@@ -2620,7 +2620,7 @@
 
 @Unstable()
 @Native("SVGPreserveAspectRatio")
-class PreserveAspectRatio extends Interceptor {
+class PreserveAspectRatio extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PreserveAspectRatio._() {
     throw new UnsupportedError("Not supported");
@@ -2702,7 +2702,7 @@
 
 @Unstable()
 @Native("SVGRect")
-class Rect extends Interceptor {
+class Rect extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Rect._() {
     throw new UnsupportedError("Not supported");
@@ -2846,7 +2846,7 @@
 
 @Unstable()
 @Native("SVGStringList")
-class StringList extends Interceptor
+class StringList extends JavaScriptObject
     with ListMixin<String>, ImmutableListMixin<String>
     implements List<String> {
   // To suppress missing implicit constructor warnings.
@@ -3619,7 +3619,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Unstable()
-abstract class Tests extends Interceptor {
+abstract class Tests extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Tests._() {
     throw new UnsupportedError("Not supported");
@@ -3791,7 +3791,7 @@
 
 @Unstable()
 @Native("SVGTransform")
-class Transform extends Interceptor {
+class Transform extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Transform._() {
     throw new UnsupportedError("Not supported");
@@ -3835,7 +3835,7 @@
 
 @Unstable()
 @Native("SVGTransformList")
-class TransformList extends Interceptor
+class TransformList extends JavaScriptObject
     with ListMixin<Transform>, ImmutableListMixin<Transform>
     implements List<Transform> {
   // To suppress missing implicit constructor warnings.
@@ -3917,7 +3917,7 @@
 
 @Unstable()
 @Native("SVGUnitTypes")
-class UnitTypes extends Interceptor {
+class UnitTypes extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory UnitTypes._() {
     throw new UnsupportedError("Not supported");
@@ -3934,7 +3934,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Unstable()
-abstract class UriReference extends Interceptor {
+abstract class UriReference extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory UriReference._() {
     throw new UnsupportedError("Not supported");
@@ -4013,7 +4013,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Unstable()
-abstract class ZoomAndPan extends Interceptor {
+abstract class ZoomAndPan extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ZoomAndPan._() {
     throw new UnsupportedError("Not supported");
diff --git a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
index 506f9e6..a7db2d5 100644
--- a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
+++ b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -13,7 +13,7 @@
 import 'dart:_native_typed_data';
 import 'dart:typed_data';
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor;
+import 'dart:_interceptors' show JavaScriptObject;
 // DO NOT EDIT - unless you are editing documentation as per:
 // https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:audio library.
@@ -81,7 +81,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AudioBuffer")
-class AudioBuffer extends Interceptor {
+class AudioBuffer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AudioBuffer._() {
     throw new UnsupportedError("Not supported");
@@ -268,7 +268,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AudioListener")
-class AudioListener extends Interceptor {
+class AudioListener extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AudioListener._() {
     throw new UnsupportedError("Not supported");
@@ -343,7 +343,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AudioParam")
-class AudioParam extends Interceptor {
+class AudioParam extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AudioParam._() {
     throw new UnsupportedError("Not supported");
@@ -379,7 +379,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AudioParamMap")
-class AudioParamMap extends Interceptor with MapMixin<String, dynamic> {
+class AudioParamMap extends JavaScriptObject with MapMixin<String, dynamic> {
   // To suppress missing implicit constructor warnings.
   factory AudioParamMap._() {
     throw new UnsupportedError("Not supported");
@@ -495,7 +495,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AudioTrack")
-class AudioTrack extends Interceptor {
+class AudioTrack extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AudioTrack._() {
     throw new UnsupportedError("Not supported");
@@ -589,7 +589,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("AudioWorkletProcessor")
-class AudioWorkletProcessor extends Interceptor {
+class AudioWorkletProcessor extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AudioWorkletProcessor._() {
     throw new UnsupportedError("Not supported");
@@ -1196,7 +1196,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("PeriodicWave")
-class PeriodicWave extends Interceptor {
+class PeriodicWave extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory PeriodicWave._() {
     throw new UnsupportedError("Not supported");
diff --git a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
index 072cfae..473059f 100644
--- a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
+++ b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -15,7 +15,7 @@
 import 'dart:_js_helper'
     show Creates, JSName, Native, Returns, convertDartClosureToJS;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+import 'dart:_interceptors' show JavaScriptObject, JSExtendableArray;
 // DO NOT EDIT - unless you are editing documentation as per:
 // https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:web_gl library.
@@ -26,7 +26,7 @@
 
 @Unstable()
 @Native("WebGLActiveInfo")
-class ActiveInfo extends Interceptor {
+class ActiveInfo extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ActiveInfo._() {
     throw new UnsupportedError("Not supported");
@@ -43,7 +43,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("ANGLEInstancedArrays,ANGLE_instanced_arrays")
-class AngleInstancedArrays extends Interceptor {
+class AngleInstancedArrays extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory AngleInstancedArrays._() {
     throw new UnsupportedError("Not supported");
@@ -68,7 +68,7 @@
 
 @Unstable()
 @Native("WebGLBuffer")
-class Buffer extends Interceptor {
+class Buffer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Buffer._() {
     throw new UnsupportedError("Not supported");
@@ -79,7 +79,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLCanvas")
-class Canvas extends Interceptor {
+class Canvas extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Canvas._() {
     throw new UnsupportedError("Not supported");
@@ -97,7 +97,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLColorBufferFloat")
-class ColorBufferFloat extends Interceptor {
+class ColorBufferFloat extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ColorBufferFloat._() {
     throw new UnsupportedError("Not supported");
@@ -108,7 +108,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLCompressedTextureASTC")
-class CompressedTextureAstc extends Interceptor {
+class CompressedTextureAstc extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CompressedTextureAstc._() {
     throw new UnsupportedError("Not supported");
@@ -175,7 +175,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLCompressedTextureATC,WEBGL_compressed_texture_atc")
-class CompressedTextureAtc extends Interceptor {
+class CompressedTextureAtc extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CompressedTextureAtc._() {
     throw new UnsupportedError("Not supported");
@@ -192,7 +192,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLCompressedTextureETC1,WEBGL_compressed_texture_etc1")
-class CompressedTextureETC1 extends Interceptor {
+class CompressedTextureETC1 extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CompressedTextureETC1._() {
     throw new UnsupportedError("Not supported");
@@ -205,7 +205,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLCompressedTextureETC")
-class CompressedTextureEtc extends Interceptor {
+class CompressedTextureEtc extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CompressedTextureEtc._() {
     throw new UnsupportedError("Not supported");
@@ -236,7 +236,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLCompressedTexturePVRTC,WEBGL_compressed_texture_pvrtc")
-class CompressedTexturePvrtc extends Interceptor {
+class CompressedTexturePvrtc extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CompressedTexturePvrtc._() {
     throw new UnsupportedError("Not supported");
@@ -255,7 +255,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLCompressedTextureS3TC,WEBGL_compressed_texture_s3tc")
-class CompressedTextureS3TC extends Interceptor {
+class CompressedTextureS3TC extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CompressedTextureS3TC._() {
     throw new UnsupportedError("Not supported");
@@ -274,7 +274,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLCompressedTextureS3TCsRGB")
-class CompressedTextureS3TCsRgb extends Interceptor {
+class CompressedTextureS3TCsRgb extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory CompressedTextureS3TCsRgb._() {
     throw new UnsupportedError("Not supported");
@@ -319,7 +319,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLDebugRendererInfo,WEBGL_debug_renderer_info")
-class DebugRendererInfo extends Interceptor {
+class DebugRendererInfo extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DebugRendererInfo._() {
     throw new UnsupportedError("Not supported");
@@ -334,7 +334,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLDebugShaders,WEBGL_debug_shaders")
-class DebugShaders extends Interceptor {
+class DebugShaders extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DebugShaders._() {
     throw new UnsupportedError("Not supported");
@@ -347,7 +347,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLDepthTexture,WEBGL_depth_texture")
-class DepthTexture extends Interceptor {
+class DepthTexture extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DepthTexture._() {
     throw new UnsupportedError("Not supported");
@@ -360,7 +360,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLDrawBuffers,WEBGL_draw_buffers")
-class DrawBuffers extends Interceptor {
+class DrawBuffers extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory DrawBuffers._() {
     throw new UnsupportedError("Not supported");
@@ -374,7 +374,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTsRGB,EXT_sRGB")
-class EXTsRgb extends Interceptor {
+class EXTsRgb extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory EXTsRgb._() {
     throw new UnsupportedError("Not supported");
@@ -393,7 +393,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTBlendMinMax,EXT_blend_minmax")
-class ExtBlendMinMax extends Interceptor {
+class ExtBlendMinMax extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ExtBlendMinMax._() {
     throw new UnsupportedError("Not supported");
@@ -408,7 +408,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTColorBufferFloat")
-class ExtColorBufferFloat extends Interceptor {
+class ExtColorBufferFloat extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ExtColorBufferFloat._() {
     throw new UnsupportedError("Not supported");
@@ -419,7 +419,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTColorBufferHalfFloat")
-class ExtColorBufferHalfFloat extends Interceptor {
+class ExtColorBufferHalfFloat extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ExtColorBufferHalfFloat._() {
     throw new UnsupportedError("Not supported");
@@ -430,7 +430,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTDisjointTimerQuery")
-class ExtDisjointTimerQuery extends Interceptor {
+class ExtDisjointTimerQuery extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ExtDisjointTimerQuery._() {
     throw new UnsupportedError("Not supported");
@@ -479,7 +479,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTDisjointTimerQueryWebGL2")
-class ExtDisjointTimerQueryWebGL2 extends Interceptor {
+class ExtDisjointTimerQueryWebGL2 extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ExtDisjointTimerQueryWebGL2._() {
     throw new UnsupportedError("Not supported");
@@ -501,7 +501,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTFragDepth,EXT_frag_depth")
-class ExtFragDepth extends Interceptor {
+class ExtFragDepth extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ExtFragDepth._() {
     throw new UnsupportedError("Not supported");
@@ -512,7 +512,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTShaderTextureLOD,EXT_shader_texture_lod")
-class ExtShaderTextureLod extends Interceptor {
+class ExtShaderTextureLod extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ExtShaderTextureLod._() {
     throw new UnsupportedError("Not supported");
@@ -523,7 +523,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("EXTTextureFilterAnisotropic,EXT_texture_filter_anisotropic")
-class ExtTextureFilterAnisotropic extends Interceptor {
+class ExtTextureFilterAnisotropic extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ExtTextureFilterAnisotropic._() {
     throw new UnsupportedError("Not supported");
@@ -539,7 +539,7 @@
 
 @Unstable()
 @Native("WebGLFramebuffer")
-class Framebuffer extends Interceptor {
+class Framebuffer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Framebuffer._() {
     throw new UnsupportedError("Not supported");
@@ -550,7 +550,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLGetBufferSubDataAsync")
-class GetBufferSubDataAsync extends Interceptor {
+class GetBufferSubDataAsync extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory GetBufferSubDataAsync._() {
     throw new UnsupportedError("Not supported");
@@ -566,7 +566,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLLoseContext,WebGLExtensionLoseContext,WEBGL_lose_context")
-class LoseContext extends Interceptor {
+class LoseContext extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory LoseContext._() {
     throw new UnsupportedError("Not supported");
@@ -581,7 +581,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OESElementIndexUint,OES_element_index_uint")
-class OesElementIndexUint extends Interceptor {
+class OesElementIndexUint extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory OesElementIndexUint._() {
     throw new UnsupportedError("Not supported");
@@ -592,7 +592,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OESStandardDerivatives,OES_standard_derivatives")
-class OesStandardDerivatives extends Interceptor {
+class OesStandardDerivatives extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory OesStandardDerivatives._() {
     throw new UnsupportedError("Not supported");
@@ -605,7 +605,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OESTextureFloat,OES_texture_float")
-class OesTextureFloat extends Interceptor {
+class OesTextureFloat extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory OesTextureFloat._() {
     throw new UnsupportedError("Not supported");
@@ -616,7 +616,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OESTextureFloatLinear,OES_texture_float_linear")
-class OesTextureFloatLinear extends Interceptor {
+class OesTextureFloatLinear extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory OesTextureFloatLinear._() {
     throw new UnsupportedError("Not supported");
@@ -627,7 +627,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OESTextureHalfFloat,OES_texture_half_float")
-class OesTextureHalfFloat extends Interceptor {
+class OesTextureHalfFloat extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory OesTextureHalfFloat._() {
     throw new UnsupportedError("Not supported");
@@ -640,7 +640,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OESTextureHalfFloatLinear,OES_texture_half_float_linear")
-class OesTextureHalfFloatLinear extends Interceptor {
+class OesTextureHalfFloatLinear extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory OesTextureHalfFloatLinear._() {
     throw new UnsupportedError("Not supported");
@@ -651,7 +651,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("OESVertexArrayObject,OES_vertex_array_object")
-class OesVertexArrayObject extends Interceptor {
+class OesVertexArrayObject extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory OesVertexArrayObject._() {
     throw new UnsupportedError("Not supported");
@@ -677,7 +677,7 @@
 
 @Unstable()
 @Native("WebGLProgram")
-class Program extends Interceptor {
+class Program extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Program._() {
     throw new UnsupportedError("Not supported");
@@ -688,7 +688,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLQuery")
-class Query extends Interceptor {
+class Query extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Query._() {
     throw new UnsupportedError("Not supported");
@@ -700,7 +700,7 @@
 
 @Unstable()
 @Native("WebGLRenderbuffer")
-class Renderbuffer extends Interceptor {
+class Renderbuffer extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Renderbuffer._() {
     throw new UnsupportedError("Not supported");
@@ -714,7 +714,8 @@
 @SupportedBrowser(SupportedBrowser.FIREFOX)
 @Unstable()
 @Native("WebGLRenderingContext")
-class RenderingContext extends Interceptor implements CanvasRenderingContext {
+class RenderingContext extends JavaScriptObject
+    implements CanvasRenderingContext {
   // To suppress missing implicit constructor warnings.
   factory RenderingContext._() {
     throw new UnsupportedError("Not supported");
@@ -1356,7 +1357,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGL2RenderingContext")
-class RenderingContext2 extends Interceptor
+class RenderingContext2 extends JavaScriptObject
     implements _WebGL2RenderingContextBase, _WebGLRenderingContextBase {
   // To suppress missing implicit constructor warnings.
   factory RenderingContext2._() {
@@ -2834,7 +2835,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLSampler")
-class Sampler extends Interceptor {
+class Sampler extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Sampler._() {
     throw new UnsupportedError("Not supported");
@@ -2845,7 +2846,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLShader")
-class Shader extends Interceptor {
+class Shader extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Shader._() {
     throw new UnsupportedError("Not supported");
@@ -2856,7 +2857,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLShaderPrecisionFormat")
-class ShaderPrecisionFormat extends Interceptor {
+class ShaderPrecisionFormat extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory ShaderPrecisionFormat._() {
     throw new UnsupportedError("Not supported");
@@ -2873,7 +2874,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLSync")
-class Sync extends Interceptor {
+class Sync extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Sync._() {
     throw new UnsupportedError("Not supported");
@@ -2884,7 +2885,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLTexture")
-class Texture extends Interceptor {
+class Texture extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory Texture._() {
     throw new UnsupportedError("Not supported");
@@ -2903,7 +2904,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLTimerQueryEXT")
-class TimerQueryExt extends Interceptor {
+class TimerQueryExt extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TimerQueryExt._() {
     throw new UnsupportedError("Not supported");
@@ -2914,7 +2915,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLTransformFeedback")
-class TransformFeedback extends Interceptor {
+class TransformFeedback extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory TransformFeedback._() {
     throw new UnsupportedError("Not supported");
@@ -2925,7 +2926,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLUniformLocation")
-class UniformLocation extends Interceptor {
+class UniformLocation extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory UniformLocation._() {
     throw new UnsupportedError("Not supported");
@@ -2936,7 +2937,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLVertexArrayObject")
-class VertexArrayObject extends Interceptor {
+class VertexArrayObject extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VertexArrayObject._() {
     throw new UnsupportedError("Not supported");
@@ -2947,7 +2948,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGLVertexArrayObjectOES")
-class VertexArrayObjectOes extends Interceptor {
+class VertexArrayObjectOes extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory VertexArrayObjectOes._() {
     throw new UnsupportedError("Not supported");
@@ -4161,7 +4162,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("WebGL2RenderingContextBase")
-abstract class _WebGL2RenderingContextBase extends Interceptor
+abstract class _WebGL2RenderingContextBase extends JavaScriptObject
     implements _WebGLRenderingContextBase {
   // To suppress missing implicit constructor warnings.
   factory _WebGL2RenderingContextBase._() {
@@ -4174,7 +4175,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-abstract class _WebGLRenderingContextBase extends Interceptor {
+abstract class _WebGLRenderingContextBase extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory _WebGLRenderingContextBase._() {
     throw new UnsupportedError("Not supported");
diff --git a/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart b/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart
index 863ba21..584b15a 100644
--- a/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart
+++ b/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart
@@ -19,7 +19,7 @@
 import 'dart:html';
 import 'dart:html_common';
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor;
+import 'dart:_interceptors' show JavaScriptObject;
 // DO NOT EDIT - unless you are editing documentation as per:
 // https://code.google.com/p/dart/wiki/ContributingHTMLDocumentation
 // Auto-generated dart:audio library.
@@ -72,7 +72,7 @@
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.SAFARI)
 @Native("Database")
-class SqlDatabase extends Interceptor {
+class SqlDatabase extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SqlDatabase._() {
     throw new UnsupportedError("Not supported");
@@ -165,7 +165,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SQLError")
-class SqlError extends Interceptor {
+class SqlError extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SqlError._() {
     throw new UnsupportedError("Not supported");
@@ -196,7 +196,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SQLResultSet")
-class SqlResultSet extends Interceptor {
+class SqlResultSet extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SqlResultSet._() {
     throw new UnsupportedError("Not supported");
@@ -213,7 +213,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 @Native("SQLResultSetRowList")
-class SqlResultSetRowList extends Interceptor
+class SqlResultSetRowList extends JavaScriptObject
     with ListMixin<Map>, ImmutableListMixin<Map>
     implements List<Map> {
   // To suppress missing implicit constructor warnings.
@@ -282,7 +282,7 @@
 // http://www.w3.org/TR/webdatabase/#sqltransaction
 @deprecated // deprecated
 @Native("SQLTransaction")
-class SqlTransaction extends Interceptor {
+class SqlTransaction extends JavaScriptObject {
   // To suppress missing implicit constructor warnings.
   factory SqlTransaction._() {
     throw new UnsupportedError("Not supported");
diff --git a/tests/lib/html/js_interop_constructor_name/error1_test.dart b/tests/lib/html/js_interop_constructor_name/error1_test.dart
index a12be51..d464c18 100644
--- a/tests/lib/html/js_interop_constructor_name/error1_test.dart
+++ b/tests/lib/html/js_interop_constructor_name/error1_test.dart
@@ -12,9 +12,14 @@
   setUpJS();
   test('dom-is-js', () {
     var e = confuse(new html.DivElement());
-    // Currently, HTML types are not [JavaScriptObject]s. We could change that
-    // by having HTML types extend JavaScriptObject, in which case we would
-    // change this expectation.
+    // Currently, HTML types are not `LegacyJavaScriptObject`s, so therefore
+    // they cannot be used with the usual `package:js` types.
     expect(e is HTMLDivElement, isFalse);
   });
+  test('dom-is-static-js', () {
+    var e = confuse(new html.DivElement());
+    // However, HTML types are `JavaScriptObject`s, so they can be used with
+    // static `package:js` types, using `@staticInterop`.
+    expect(e is StaticHTMLDivElement, isTrue);
+  });
 }
diff --git a/tests/lib/html/js_interop_constructor_name/error2_test.dart b/tests/lib/html/js_interop_constructor_name/error2_test.dart
index 365e418..e2ef8d3 100644
--- a/tests/lib/html/js_interop_constructor_name/error2_test.dart
+++ b/tests/lib/html/js_interop_constructor_name/error2_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:html' as html;
-
 import 'package:expect/minitest.dart';
 
 import 'util.dart';
@@ -16,5 +14,6 @@
     // to Interceptor, but should be added to the class that implements all
     // the JS-interop methods.
     expect(e is HTMLDivElement, isFalse);
+    expect(e is StaticHTMLDivElement, isFalse);
   });
 }
diff --git a/tests/lib/html/js_interop_constructor_name/method_test.dart b/tests/lib/html/js_interop_constructor_name/method_test.dart
index 9781829..3d3099f 100644
--- a/tests/lib/html/js_interop_constructor_name/method_test.dart
+++ b/tests/lib/html/js_interop_constructor_name/method_test.dart
@@ -30,4 +30,14 @@
     var e = confuse(new html.DivElement());
     Expect.type<html.DivElement>(e.clone(false));
   });
+
+  test('js-call-static-js-method', () {
+    StaticHTMLDivElement e = confuse(makeDiv('hello'));
+    expect(e.bar(), equals('hello'));
+  });
+
+  test('dom-call-static-js-method', () {
+    StaticHTMLDivElement e = confuse(new html.DivElement());
+    Expect.type<html.DivElement>(e.cloneNode(false));
+  });
 }
diff --git a/tests/lib/html/js_interop_constructor_name/util.dart b/tests/lib/html/js_interop_constructor_name/util.dart
index 3ec4563..135518d 100644
--- a/tests/lib/html/js_interop_constructor_name/util.dart
+++ b/tests/lib/html/js_interop_constructor_name/util.dart
@@ -20,6 +20,15 @@
   external String bar();
 }
 
+@JS('Foo.HTMLDivElement')
+@staticInterop
+class StaticHTMLDivElement {}
+
+extension StaticHTMLDivElementExtension on StaticHTMLDivElement {
+  external String bar();
+  external StaticHTMLDivElement cloneNode(bool? deep);
+}
+
 @pragma('dart2js:noInline')
 @pragma('dart2js:assumeDynamic')
 confuse(x) => x;
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index ccc6171..46bdedf 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -11,6 +11,9 @@
 developer/timeline_test: Skip # Not supported
 isolate/issue_24243_parent_isolate_test: Skip # Requires checked mode
 
+[ $runtime == d8 ]
+js/js_util/javascriptobject_extensions_test.dart: SkipByDesign # Uses dart:html.
+
 [ $runtime == dart_precompiled ]
 isolate/package_config_getter_test: SkipByDesign # AOT mode doesn't preserve package structure.
 
diff --git a/tests/lib_2/html/js_interop_constructor_name/error1_test.dart b/tests/lib_2/html/js_interop_constructor_name/error1_test.dart
index f28cc09..19f516c 100644
--- a/tests/lib_2/html/js_interop_constructor_name/error1_test.dart
+++ b/tests/lib_2/html/js_interop_constructor_name/error1_test.dart
@@ -14,9 +14,14 @@
   setUpJS();
   test('dom-is-js', () {
     var e = confuse(new html.DivElement());
-    // Currently, HTML types are not [JavaScriptObject]s. We could change that
-    // by having HTML types extend JavaScriptObject, in which case we would
-    // change this expectation.
+    // Currently, HTML types are not `LegacyJavaScriptObject`s, so therefore
+    // they cannot be used with the usual `package:js` types.
     expect(e is HTMLDivElement, isFalse);
   });
+  test('dom-is-static-js', () {
+    var e = confuse(new html.DivElement());
+    // However, HTML types are `JavaScriptObject`s, so they can be used with
+    // static `package:js` types, using `@staticInterop`.
+    expect(e is StaticHTMLDivElement, isTrue);
+  });
 }
diff --git a/tests/lib_2/html/js_interop_constructor_name/error2_test.dart b/tests/lib_2/html/js_interop_constructor_name/error2_test.dart
index 078a870..85b5117 100644
--- a/tests/lib_2/html/js_interop_constructor_name/error2_test.dart
+++ b/tests/lib_2/html/js_interop_constructor_name/error2_test.dart
@@ -4,8 +4,6 @@
 
 // @dart = 2.9
 
-import 'dart:html' as html;
-
 import 'package:expect/minitest.dart';
 
 import 'util.dart';
@@ -18,5 +16,6 @@
     // to Interceptor, but should be added to the class that implements all
     // the JS-interop methods.
     expect(e is HTMLDivElement, isFalse);
+    expect(e is StaticHTMLDivElement, isFalse);
   });
 }
diff --git a/tests/lib_2/html/js_interop_constructor_name/method_test.dart b/tests/lib_2/html/js_interop_constructor_name/method_test.dart
index a7fd842..251bf8d 100644
--- a/tests/lib_2/html/js_interop_constructor_name/method_test.dart
+++ b/tests/lib_2/html/js_interop_constructor_name/method_test.dart
@@ -32,4 +32,14 @@
     var e = confuse(new html.DivElement());
     Expect.type<html.DivElement>(e.clone(false));
   });
+
+  test('js-call-static-js-method', () {
+    StaticHTMLDivElement e = confuse(makeDiv('hello'));
+    expect(e.bar(), equals('hello'));
+  });
+
+  test('dom-call-static-js-method', () {
+    StaticHTMLDivElement e = confuse(new html.DivElement());
+    Expect.type<html.DivElement>(e.cloneNode(false));
+  });
 }
diff --git a/tests/lib_2/html/js_interop_constructor_name/util.dart b/tests/lib_2/html/js_interop_constructor_name/util.dart
index c98f612..bdb5602 100644
--- a/tests/lib_2/html/js_interop_constructor_name/util.dart
+++ b/tests/lib_2/html/js_interop_constructor_name/util.dart
@@ -22,6 +22,15 @@
   external String bar();
 }
 
+@JS('Foo.HTMLDivElement')
+@staticInterop
+class StaticHTMLDivElement {}
+
+extension StaticHTMLDivElementExtension on StaticHTMLDivElement {
+  external String bar();
+  external StaticHTMLDivElement cloneNode(bool deep);
+}
+
 @pragma('dart2js:noInline')
 @pragma('dart2js:assumeDynamic')
 confuse(x) => x;
diff --git a/tests/lib_2/lib_2.status b/tests/lib_2/lib_2.status
index d79f2ba..bef1d69 100644
--- a/tests/lib_2/lib_2.status
+++ b/tests/lib_2/lib_2.status
@@ -11,6 +11,9 @@
 developer/timeline_test: Skip # Not supported
 isolate/issue_24243_parent_isolate_test: Skip # Requires checked mode
 
+[ $runtime == d8 ]
+js/js_util/javascriptobject_extensions_test.dart: SkipByDesign # Uses dart:html.
+
 [ $runtime == dart_precompiled ]
 isolate/package_config_getter_test: SkipByDesign # AOT mode doesn't preserve package structure.
 
diff --git a/tests/modular/static_interop_erasure/.packages b/tests/modular/static_interop_erasure/.packages
new file mode 100644
index 0000000..fce126f
--- /dev/null
+++ b/tests/modular/static_interop_erasure/.packages
@@ -0,0 +1 @@
+js:../../../pkg/js/lib
diff --git a/tests/modular/static_interop_erasure/main.dart b/tests/modular/static_interop_erasure/main.dart
new file mode 100644
index 0000000..80ccc3b
--- /dev/null
+++ b/tests/modular/static_interop_erasure/main.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'static_interop.dart';
+
+void main() {
+  setUp();
+  var staticJs = StaticJSClass.factory();
+}
diff --git a/tests/modular/static_interop_erasure/modules.yaml b/tests/modular/static_interop_erasure/modules.yaml
new file mode 100644
index 0000000..6d1a988
--- /dev/null
+++ b/tests/modular/static_interop_erasure/modules.yaml
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+#
+# Test that modular compilation still works with static interop classes that
+# contain factories.
+dependencies:
+  main: static_interop
+  static_interop: js
diff --git a/tests/modular/static_interop_erasure/static_interop.dart b/tests/modular/static_interop_erasure/static_interop.dart
new file mode 100644
index 0000000..a5c93c4
--- /dev/null
+++ b/tests/modular/static_interop_erasure/static_interop.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@JS()
+library static_interop;
+
+import 'package:js/js.dart';
+
+@JS()
+external void eval(String code);
+
+@JS('JSClass')
+@staticInterop
+class StaticJSClass {
+  external StaticJSClass();
+  factory StaticJSClass.factory() {
+    return StaticJSClass();
+  }
+}
+
+void setUp() {
+  eval('''function JSClass() {}''');
+}
diff --git a/tests/web/internal/javascriptobject_extensions_test.dart b/tests/web/internal/javascriptobject_extensions_test.dart
index 4edd79d..90ad415 100644
--- a/tests/web/internal/javascriptobject_extensions_test.dart
+++ b/tests/web/internal/javascriptobject_extensions_test.dart
@@ -12,9 +12,14 @@
 import 'package:expect/expect.dart' show hasUnsoundNullSafety;
 import 'package:expect/minitest.dart';
 
-import 'dart:typed_data';
+import 'dart:html' show Window;
+import 'dart:typed_data' show ByteBuffer;
 import 'dart:_interceptors'
-    show JavaScriptObject, UnknownJavaScriptObject, JSObject;
+    show
+        LegacyJavaScriptObject,
+        JavaScriptObject,
+        UnknownJavaScriptObject,
+        JSObject;
 
 @JS()
 external void eval(String code);
@@ -46,6 +51,11 @@
 @JS('arrayBuffer')
 external dynamic get arrayBufferDynamic;
 
+external Window get window;
+
+@JS('window')
+external dynamic get windowDynamic;
+
 // Extension on JavaScriptObject. In the future, when extension types are
 // introduced, this will be explicitly disallowed.
 extension JavaScriptObjectExtension on JavaScriptObject {
@@ -112,19 +122,33 @@
   expect(javaScriptObject is DartClass, false);
   runtimeIsAndAs<DartClass>(javaScriptObject, false);
 
-  // Native objects cannot be casted to or from JavaScriptObject.
+  // Web Native classes are subclasses of JavaScriptObject, but not
+  // LegacyJavaScriptObject.
+  expect(window is JavaScriptObject, true);
+  runtimeIsAndAs<JavaScriptObject>(window, true);
+  runtimeIsAndAs<JavaScriptObject>(windowDynamic, true);
+  javaScriptObject = jsObj as JavaScriptObject;
+  expect(javaScriptObject is Window, false);
+  runtimeIsAndAs<Window>(javaScriptObject, false);
+
+  expect(window is LegacyJavaScriptObject, false);
+  runtimeIsAndAs<LegacyJavaScriptObject>(window, false);
+  runtimeIsAndAs<LegacyJavaScriptObject>(windowDynamic, false);
+  var legacyJavaScriptObject = jsObj as LegacyJavaScriptObject;
+  expect(legacyJavaScriptObject is Window, false);
+  runtimeIsAndAs<Window>(legacyJavaScriptObject, false);
+
+  // Non-web Native classes like those in `dart:typed_data` are not subclasses
+  // of JavaScriptObject.
   expect(arrayBuffer is JavaScriptObject, false);
   runtimeIsAndAs<JavaScriptObject>(arrayBuffer, false);
+  runtimeIsAndAs<JavaScriptObject>(arrayBufferDynamic, false);
   expect(javaScriptObject is ByteBuffer, false);
   runtimeIsAndAs<ByteBuffer>(javaScriptObject, false);
 
-  // Dynamic native objects are intercepted and cannot be casted to
-  // JavaScriptObject.
-  runtimeIsAndAs<JavaScriptObject>(arrayBufferDynamic, false);
-
   // Make sure `Object` methods work with JavaScriptObject like they do with JS
   // interop objects.
-  expect(anonymousObj == javaScriptObject, true);
+  expect(javaScriptObject == jsObj, true);
   expect(javaScriptObject.hashCode, isNotNull);
   expect(javaScriptObject.toString, isNotNull);
   expect(javaScriptObject.noSuchMethod, isNotNull);
diff --git a/tests/web/internal/rti/js_interop_subtype_test.dart b/tests/web/internal/rti/js_interop_subtype_test.dart
index 66010da..ffcb31c 100644
--- a/tests/web/internal/rti/js_interop_subtype_test.dart
+++ b/tests/web/internal/rti/js_interop_subtype_test.dart
@@ -17,6 +17,6 @@
   eval(r'''
       function JSClass() {}
       ''');
-  Expect.type<JavaScriptObject>(JSClass());
-  Expect.type<List<JavaScriptObject>>(<JSClass>[]);
+  Expect.type<LegacyJavaScriptObject>(JSClass());
+  Expect.type<List<LegacyJavaScriptObject>>(<JSClass>[]);
 }
diff --git a/tests/web/native/error_safeToString_test.dart b/tests/web/native/error_safeToString_test.dart
index ecb3544..333b9c7 100644
--- a/tests/web/native/error_safeToString_test.dart
+++ b/tests/web/native/error_safeToString_test.dart
@@ -7,7 +7,7 @@
 import 'dart:_interceptors'
     show
         Interceptor,
-        JavaScriptObject,
+        LegacyJavaScriptObject,
         PlainJavaScriptObject,
         UnknownJavaScriptObject;
 
diff --git a/tests/web/native/jsobject_test.dart b/tests/web/native/jsobject_test.dart
index 0b769d0..5604920 100644
--- a/tests/web/native/jsobject_test.dart
+++ b/tests/web/native/jsobject_test.dart
@@ -8,7 +8,7 @@
     show
         JSObject, // The interface, which may be re-exported by a
         // js-interop library.
-        JavaScriptObject, //   The interceptor abstract class.
+        LegacyJavaScriptObject, //   The interceptor abstract class.
         PlainJavaScriptObject, //     The interceptor concrete class.
         UnknownJavaScriptObject, //     The interceptor concrete class.
         Interceptor;
@@ -47,21 +47,21 @@
 static_test() {
   var x = makeA();
   Expect.isTrue(x is JSObject);
-  Expect.isTrue(x is JavaScriptObject);
+  Expect.isTrue(x is LegacyJavaScriptObject);
   Expect.isTrue(x is PlainJavaScriptObject);
   Expect.isTrue(x is! UnknownJavaScriptObject);
   Expect.equals(JSObject, x.runtimeType);
 
   x = makeB();
   Expect.isTrue(x is JSObject);
-  Expect.isTrue(x is JavaScriptObject);
+  Expect.isTrue(x is LegacyJavaScriptObject);
   Expect.isTrue(x is! PlainJavaScriptObject);
   Expect.isTrue(x is UnknownJavaScriptObject);
   Expect.equals(JSObject, x.runtimeType);
 
   x = makeQ();
   Expect.isFalse(x is JSObject);
-  Expect.isFalse(x is JavaScriptObject);
+  Expect.isFalse(x is LegacyJavaScriptObject);
   Expect.isFalse(x is PlainJavaScriptObject);
   Expect.isFalse(x is UnknownJavaScriptObject);
   Expect.isFalse(x.runtimeType == JSObject);
@@ -71,27 +71,27 @@
 dynamic_test() {
   var x = makeA();
   var isJSObject = new Is<JSObject>().check;
-  var isJavaScriptObject = new Is<JavaScriptObject>().check;
+  var isLegacyJavaScriptObject = new Is<LegacyJavaScriptObject>().check;
   var isPlainJavaScriptObject = new Is<PlainJavaScriptObject>().check;
   var isUnknownJavaScriptObject = new Is<UnknownJavaScriptObject>().check;
   var isQ = new Is<Q>().check;
 
   Expect.isTrue(isJSObject(x));
-  Expect.isTrue(isJavaScriptObject(x));
+  Expect.isTrue(isLegacyJavaScriptObject(x));
   Expect.isTrue(isPlainJavaScriptObject(x));
   Expect.isTrue(!isUnknownJavaScriptObject(x));
   Expect.equals(JSObject, x.runtimeType);
 
   x = makeB();
   Expect.isTrue(isJSObject(x));
-  Expect.isTrue(isJavaScriptObject(x));
+  Expect.isTrue(isLegacyJavaScriptObject(x));
   Expect.isTrue(!isPlainJavaScriptObject(x));
   Expect.isTrue(isUnknownJavaScriptObject(x));
   Expect.equals(JSObject, x.runtimeType);
 
   x = makeQ();
   Expect.isFalse(isJSObject(x));
-  Expect.isFalse(isJavaScriptObject(x));
+  Expect.isFalse(isLegacyJavaScriptObject(x));
   Expect.isFalse(isPlainJavaScriptObject(x));
   Expect.isFalse(isUnknownJavaScriptObject(x));
   Expect.isTrue(isQ(x));
diff --git a/tests/web/native/static_interop_erasure/factory_stub_test.dart b/tests/web/native/static_interop_erasure/factory_stub_test.dart
new file mode 100644
index 0000000..71fe516
--- /dev/null
+++ b/tests/web/native/static_interop_erasure/factory_stub_test.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that factory methods with bodies are stubbed correctly in static interop
+// type erasure.
+
+@JS()
+library factory_stub_test;
+
+import 'dart:_interceptors' show JavaScriptObject;
+
+import 'package:js/js.dart';
+
+import '../native_testing.dart';
+import '../native_testing.dart' as native_testing;
+
+NativeClass makeNativeClass() native;
+
+@Native('NativeClass')
+class NativeClass extends JavaScriptObject {
+  factory NativeClass() => makeNativeClass();
+}
+
+@JS('NativeClass')
+@staticInterop
+class StaticNativeClass {
+  external StaticNativeClass();
+  factory StaticNativeClass.redirectingFactory() = StaticNativeClass;
+  factory StaticNativeClass.simpleFactory() => StaticNativeClass();
+  factory StaticNativeClass.factoryWithParam(
+          StaticNativeClass staticNativeClass) =>
+      staticNativeClass;
+  // This and `StaticNativeClassCopy.nestedFactory` exist to ensure that we
+  // cover the case where invocations on factories are visible before their
+  // declarations in the AST. This will test whether we correctly create the
+  // stub even if we haven't visited the declaration yet.
+  factory StaticNativeClass.nestedFactory() {
+    StaticNativeClassCopy.nestedFactory();
+    return StaticNativeClass();
+  }
+}
+
+@JS('NativeClass')
+@staticInterop
+class StaticNativeClassCopy {
+  external StaticNativeClassCopy();
+  factory StaticNativeClassCopy.nestedFactory() {
+    StaticNativeClass.simpleFactory();
+    return StaticNativeClassCopy();
+  }
+}
+
+void main() {
+  nativeTesting();
+  native_testing.JS('', r'''
+    (function(){
+      function NativeClass() {}
+      self.NativeClass = NativeClass;
+      self.makeNativeClass = function(){return new NativeClass()};
+      self.nativeConstructor(NativeClass);
+    })()
+  ''');
+  applyTestExtensions(['NativeClass']);
+
+  // Make the Native class live.
+  NativeClass();
+  // Invoke factories and ensure they're typed correctly through assignment.
+  StaticNativeClass staticNativeClass = StaticNativeClass.redirectingFactory();
+  staticNativeClass = StaticNativeClass.simpleFactory();
+  staticNativeClass = StaticNativeClass.factoryWithParam(staticNativeClass);
+  staticNativeClass = StaticNativeClass.nestedFactory();
+}
diff --git a/tests/web/native/static_interop_erasure/type_test.dart b/tests/web/native/static_interop_erasure/type_test.dart
new file mode 100644
index 0000000..c3081b8
--- /dev/null
+++ b/tests/web/native/static_interop_erasure/type_test.dart
@@ -0,0 +1,244 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that the type and subtyping relationships between static interop,
+// non-static interop, and Native classes are well-formed.
+
+@JS()
+library type_test;
+
+import 'dart:_interceptors' show JavaScriptObject;
+
+import 'package:expect/expect.dart' show hasUnsoundNullSafety;
+import 'package:expect/minitest.dart';
+import 'package:js/js.dart';
+
+import '../native_testing.dart';
+import '../native_testing.dart' as native_testing;
+
+NativeClass makeNativeClass() native;
+
+@Native('NativeClass')
+class NativeClass extends JavaScriptObject {
+  factory NativeClass() => makeNativeClass();
+}
+
+@JS('NativeClass')
+@staticInterop
+class StaticNativeClass {
+  external StaticNativeClass();
+}
+
+@JS()
+class JSClass {
+  external JSClass();
+}
+
+@JS('JSClass')
+@staticInterop
+class StaticJSClass {
+  external StaticJSClass();
+}
+
+@JS()
+@anonymous
+class AnonymousClass {
+  external factory();
+}
+
+@JS()
+@staticInterop
+class GenericStaticJSClass<T> {}
+
+NativeClass returnNativeClass() => throw '';
+
+StaticNativeClass returnStaticNativeClass() => throw '';
+
+JSClass returnJSClass() => throw '';
+
+StaticJSClass returnStaticJSClass() => throw '';
+
+AnonymousClass returnAnonymousClass() => throw '';
+
+GenericStaticJSClass<int> returnGenericStaticJSClassInt() => throw '';
+
+StaticJSClass? returnNullableStaticJSClass() => throw '';
+
+void main() {
+  nativeTesting();
+  native_testing.JS('', r'''
+    (function(){
+      function NativeClass() {}
+      self.NativeClass = NativeClass;
+      self.makeNativeClass = function(){return new NativeClass()};
+      self.nativeConstructor(NativeClass);
+      function JSClass() {}
+      self.JSClass = JSClass;
+    })()
+  ''');
+  applyTestExtensions(['NativeClass']);
+
+  var nativeClass = NativeClass();
+  var staticNativeClass = StaticNativeClass();
+  var jsClass = JSClass();
+  var staticJsClass = StaticJSClass();
+  var anonymousClass = AnonymousClass();
+
+  // Test that nullability of the type is respected in erasure.
+  expect(null is StaticJSClass?, true);
+  expect(confuse(null) is StaticJSClass?, true);
+  expect(() => null as StaticJSClass?, returnsNormally);
+  expect(null is StaticJSClass, false);
+  expect(confuse(null) is StaticJSClass, false);
+  expect(() => null as StaticJSClass,
+      hasUnsoundNullSafety ? returnsNormally : throws);
+
+  // Native objects can be interop'd with static interop classes.
+  expect(nativeClass is StaticNativeClass, true);
+  expect(confuse(nativeClass) is StaticNativeClass, true);
+  expect(() => nativeClass as StaticNativeClass, returnsNormally);
+
+  expect(staticNativeClass is NativeClass, true);
+  expect(confuse(staticNativeClass) is NativeClass, true);
+  expect(() => staticNativeClass as NativeClass, returnsNormally);
+
+  // Likewise, non-native JS objects can be interop'd with static interop
+  // classes as well.
+  expect(jsClass is StaticJSClass, true);
+  expect(confuse(jsClass) is StaticJSClass, true);
+  expect(() => jsClass as StaticJSClass, returnsNormally);
+
+  expect(staticJsClass is JSClass, true);
+  expect(confuse(staticJsClass) is JSClass, true);
+  expect(() => staticJsClass as JSClass, returnsNormally);
+
+  expect(anonymousClass is StaticJSClass, true);
+  expect(confuse(anonymousClass) is StaticJSClass, true);
+  expect(() => anonymousClass as StaticJSClass, returnsNormally);
+
+  expect(staticJsClass is AnonymousClass, true);
+  expect(confuse(staticJsClass) is AnonymousClass, true);
+  expect(() => staticJsClass as AnonymousClass, returnsNormally);
+
+  // With erasure, all static interop classes become the same type, so you can
+  // cast either interop or native objects to them regardless of the underlying
+  // class.
+  expect(staticNativeClass is StaticJSClass, true);
+  expect(confuse(staticNativeClass) is StaticJSClass, true);
+  expect(() => staticNativeClass as StaticJSClass, returnsNormally);
+
+  expect(staticJsClass is StaticNativeClass, true);
+  expect(confuse(staticJsClass) is StaticNativeClass, true);
+  expect(() => staticJsClass as StaticNativeClass, returnsNormally);
+
+  expect(nativeClass is StaticJSClass, true);
+  expect(confuse(nativeClass) is StaticJSClass, true);
+  expect(() => nativeClass as StaticJSClass, returnsNormally);
+
+  expect(jsClass is StaticNativeClass, true);
+  expect(confuse(jsClass) is StaticNativeClass, true);
+  expect(() => jsClass as StaticNativeClass, returnsNormally);
+
+  expect(anonymousClass is StaticNativeClass, true);
+  expect(confuse(anonymousClass) is StaticNativeClass, true);
+  expect(() => anonymousClass as StaticNativeClass, returnsNormally);
+
+  // You cannot, however, always cast from a static interop type to an interop
+  // type or a native type. That will depend on whether the object is an interop
+  // object or a native object.
+  expect(staticNativeClass is JSClass, false);
+  expect(confuse(staticNativeClass) is JSClass, false);
+  expect(() => staticNativeClass as JSClass, throws);
+
+  expect(staticNativeClass is AnonymousClass, false);
+  expect(confuse(staticNativeClass) is AnonymousClass, false);
+  expect(() => staticNativeClass as AnonymousClass, throws);
+
+  expect(staticJsClass is NativeClass, false);
+  expect(confuse(staticJsClass) is NativeClass, false);
+  expect(() => staticJsClass as NativeClass, throws);
+
+  // Subtyping rules.
+
+  // Note that erasure ignores all static class type parameters so this
+  // comparison becomes
+  // `JavaScriptObject Function() is JavaScriptObject Function()`. This behavior
+  // is similar to non-static interop classes.
+  expect(
+      returnGenericStaticJSClassInt is GenericStaticJSClass<String> Function(),
+      true);
+  expect(
+      confuse(returnGenericStaticJSClassInt) is GenericStaticJSClass<String>
+          Function(),
+      true);
+  expect(
+      () => returnGenericStaticJSClassInt as GenericStaticJSClass<String>
+          Function(),
+      returnsNormally);
+
+  // Test that nullability is respected.
+  expect(returnStaticJSClass is StaticJSClass? Function(), true);
+  expect(confuse(returnStaticJSClass) is StaticJSClass? Function(), true);
+  expect(returnNullableStaticJSClass is StaticJSClass Function(),
+      hasUnsoundNullSafety);
+  expect(confuse(returnNullableStaticJSClass) is StaticJSClass Function(),
+      hasUnsoundNullSafety);
+
+  // static interop class A <: static interop class A
+  expect(returnStaticNativeClass is StaticNativeClass Function(), true);
+  expect(
+      confuse(returnStaticNativeClass) is StaticNativeClass Function(), true);
+  expect(returnStaticJSClass is StaticJSClass Function(), true);
+  expect(confuse(returnStaticJSClass) is StaticJSClass Function(), true);
+
+  // static interop class A <: static interop class B
+  expect(returnStaticNativeClass is StaticJSClass Function(), true);
+  expect(confuse(returnStaticNativeClass) is StaticJSClass Function(), true);
+  expect(returnStaticJSClass is StaticNativeClass Function(), true);
+  expect(confuse(returnStaticJSClass) is StaticNativeClass Function(), true);
+
+  // static interop class !<: native class
+  expect(returnStaticNativeClass is NativeClass Function(), false);
+  expect(confuse(returnStaticNativeClass) is NativeClass Function(), false);
+  expect(returnStaticJSClass is NativeClass Function(), false);
+  expect(confuse(returnStaticJSClass) is NativeClass Function(), false);
+
+  // static interop class !<: package:js class
+  expect(returnStaticNativeClass is JSClass Function(), false);
+  expect(confuse(returnStaticNativeClass) is JSClass Function(), false);
+  expect(returnStaticJSClass is JSClass Function(), false);
+  expect(confuse(returnStaticJSClass) is JSClass Function(), false);
+
+  // static interop class !<: anonymous class
+  expect(returnStaticNativeClass is AnonymousClass Function(), false);
+  expect(confuse(returnStaticNativeClass) is AnonymousClass Function(), false);
+  expect(returnStaticJSClass is AnonymousClass Function(), false);
+  expect(confuse(returnStaticJSClass) is AnonymousClass Function(), false);
+
+  // native class <: static interop class
+  expect(returnNativeClass is StaticJSClass Function(), true);
+  expect(confuse(returnNativeClass) is StaticJSClass Function(), true);
+  expect(returnNativeClass is StaticNativeClass Function(), true);
+  expect(confuse(returnNativeClass) is StaticNativeClass Function(), true);
+
+  // package:js class <: static interop class
+  // TODO(46456): The runtime check using `confuse` does not fail, whereas the
+  // compile-time check does on dart2js.
+  // expect(returnJSClass is StaticJSClass Function(), true);
+  expect(confuse(returnJSClass) is StaticJSClass Function(), true);
+  // TODO(46456): The runtime check using `confuse` does not fail, whereas the
+  // compile-time check does on dart2js.
+  // expect(returnJSClass is StaticNativeClass Function(), true);
+  expect(confuse(returnJSClass) is StaticNativeClass Function(), true);
+
+  // anonymous class <: static interop class
+  // TODO(46456): The runtime check using `confuse` does not fail, whereas the
+  // compile-time check does on dart2js.
+  // expect(returnAnonymousClass is StaticJSClass Function(), true);
+  expect(confuse(returnAnonymousClass) is StaticJSClass Function(), true);
+  // TODO(46456): The runtime check using `confuse` does not fail, whereas the
+  // compile-time check does on dart2js.
+  // expect(returnAnonymousClass is StaticNativeClass Function(), true);
+  expect(confuse(returnAnonymousClass) is StaticNativeClass Function(), true);
+}
diff --git a/tests/web/native/static_interop_erasure/use_erased_type_members_test.dart b/tests/web/native/static_interop_erasure/use_erased_type_members_test.dart
new file mode 100644
index 0000000..99c446d
--- /dev/null
+++ b/tests/web/native/static_interop_erasure/use_erased_type_members_test.dart
@@ -0,0 +1,157 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that a static interop class can be used in place of a Native class and
+// its static members work as expected post-erasure.
+
+@JS()
+library use_erased_type_members_test;
+
+import 'dart:_interceptors' show JavaScriptObject;
+
+import 'package:expect/minitest.dart';
+import 'package:js/js.dart';
+
+import '../native_testing.dart';
+import '../native_testing.dart' as native_testing;
+
+NativeClass makeNativeClass() native;
+
+@Native('NativeClass')
+class NativeClass extends JavaScriptObject {
+  factory NativeClass() => makeNativeClass();
+}
+
+@JS()
+@staticInterop
+class Parent {}
+
+extension ParentExtension on Parent {
+  external String parentExternalField;
+  external String get parentExternalGetSet;
+  external set parentExternalGetSet(String val);
+  external String parentExternalMethod();
+
+  String get parentGetSet => this.parentExternalGetSet;
+  set parentGetSet(String val) => this.parentExternalGetSet = val;
+  String parentMethod() => 'parentMethod';
+}
+
+@JS()
+@staticInterop
+class Interface {}
+
+extension InterfaceExtension on Interface {
+  external String interfaceExternalField;
+  external String get interfaceExternalGetSet;
+  external set interfaceExternalGetSet(String val);
+  external String interfaceExternalMethod();
+
+  String get interfaceGetSet => this.interfaceExternalGetSet;
+  set interfaceGetSet(String val) => this.interfaceExternalGetSet = val;
+  String interfaceMethod() => 'interfaceMethod';
+}
+
+@JS('NativeClass')
+@staticInterop
+class StaticJSClass extends Parent implements Interface {
+  external StaticJSClass();
+  external StaticJSClass.namedConstructor();
+  external factory StaticJSClass.externalFactory();
+  factory StaticJSClass.redirectingFactory() = StaticJSClass;
+
+  external static String externalStaticField;
+  external static String get externalStaticGetSet;
+  external static set externalStaticGetSet(String val);
+  external static String externalStaticMethod();
+}
+
+extension StaticJSClassExtension on StaticJSClass {
+  external String externalField;
+  external String get externalGetSet;
+  external set externalGetSet(String val);
+  external String externalMethod();
+
+  String get getSet => this.externalGetSet;
+  set getSet(String val) => this.externalGetSet = val;
+  String method() => 'method';
+}
+
+void main() {
+  nativeTesting();
+  native_testing.JS('', r'''
+    (function(){
+      function NativeClass() {
+        this.externalField = 'externalField';
+        this.externalGetSet = this.externalField;
+        this.externalMethod = function() { return 'externalMethod'; };
+
+        this.parentExternalField = 'parentExternalField';
+        this.parentExternalGetSet = this.parentExternalField;
+        this.parentExternalMethod = function() {
+          return 'parentExternalMethod';
+        };
+
+        this.interfaceExternalField = 'interfaceExternalField';
+        this.interfaceExternalGetSet = this.interfaceExternalField;
+        this.interfaceExternalMethod = function() {
+          return 'interfaceExternalMethod';
+        };
+      }
+      NativeClass.externalStaticField = 'externalStaticField';
+      NativeClass.externalStaticGetSet = NativeClass.externalStaticField;
+      NativeClass.externalStaticMethod = function() {
+        return 'externalStaticMethod';
+      };
+      self.NativeClass = NativeClass;
+      self.makeNativeClass = function(){return new NativeClass()};
+      self.nativeConstructor(NativeClass);
+    })()
+  ''');
+  applyTestExtensions(['NativeClass']);
+
+  // NativeClass needs to be live, so it can be correctly intercepted.
+  NativeClass();
+  // Invoke constructors and ensure they're typed correctly.
+  StaticJSClass staticJs = StaticJSClass();
+  staticJs = StaticJSClass.namedConstructor();
+  staticJs = StaticJSClass.externalFactory();
+  staticJs = StaticJSClass.redirectingFactory();
+
+  // Invoke external static members.
+  expect(StaticJSClass.externalStaticField, 'externalStaticField');
+  StaticJSClass.externalStaticGetSet = 'externalStaticGetSet';
+  expect(StaticJSClass.externalStaticGetSet, 'externalStaticGetSet');
+  expect(StaticJSClass.externalStaticMethod(), 'externalStaticMethod');
+
+  // Use extension members.
+  expect(staticJs.externalField, 'externalField');
+  staticJs.externalGetSet = 'externalGetSet';
+  expect(staticJs.externalGetSet, 'externalGetSet');
+  expect(staticJs.externalMethod(), 'externalMethod');
+
+  staticJs.getSet = 'getSet';
+  expect(staticJs.getSet, 'getSet');
+  expect(staticJs.method(), 'method');
+
+  // Use parent extension members.
+  expect(staticJs.parentExternalField, 'parentExternalField');
+  staticJs.parentExternalGetSet = 'parentExternalGetSet';
+  expect(staticJs.parentExternalGetSet, 'parentExternalGetSet');
+  expect(staticJs.parentExternalMethod(), 'parentExternalMethod');
+
+  staticJs.parentGetSet = 'parentGetSet';
+  expect(staticJs.parentGetSet, 'parentGetSet');
+  expect(staticJs.parentMethod(), 'parentMethod');
+
+  // Use interface extension members.
+  expect(staticJs.interfaceExternalField, 'interfaceExternalField');
+  staticJs.interfaceExternalGetSet = 'interfaceExternalGetSet';
+  expect(staticJs.interfaceExternalGetSet, 'interfaceExternalGetSet');
+  expect(staticJs.interfaceExternalMethod(), 'interfaceExternalMethod');
+
+  staticJs.interfaceGetSet = 'interfaceGetSet';
+  expect(staticJs.interfaceGetSet, 'interfaceGetSet');
+  expect(staticJs.interfaceMethod(), 'interfaceMethod');
+}
diff --git a/tests/web_2/internal/javascriptobject_extensions_test.dart b/tests/web_2/internal/javascriptobject_extensions_test.dart
index 6189667..dc912cd 100644
--- a/tests/web_2/internal/javascriptobject_extensions_test.dart
+++ b/tests/web_2/internal/javascriptobject_extensions_test.dart
@@ -11,9 +11,14 @@
 import 'package:js/js_util.dart';
 import 'package:expect/minitest.dart';
 
-import 'dart:typed_data';
+import 'dart:html' show Window;
+import 'dart:typed_data' show ByteBuffer;
 import 'dart:_interceptors'
-    show JavaScriptObject, UnknownJavaScriptObject, JSObject;
+    show
+        LegacyJavaScriptObject,
+        JavaScriptObject,
+        UnknownJavaScriptObject,
+        JSObject;
 
 @JS()
 external void eval(String code);
@@ -45,6 +50,11 @@
 @JS('arrayBuffer')
 external dynamic get arrayBufferDynamic;
 
+external Window get window;
+
+@JS('window')
+external dynamic get windowDynamic;
+
 // Extension on JavaScriptObject. In the future, when extension types are
 // introduced, this will be explicitly disallowed.
 extension JavaScriptObjectExtension on JavaScriptObject {
@@ -109,19 +119,33 @@
   expect(javaScriptObject is DartClass, false);
   runtimeIsAndAs<DartClass>(javaScriptObject, false);
 
-  // Native objects cannot be casted to or from JavaScriptObject.
+  // Web Native classes are subclasses of JavaScriptObject, but not
+  // LegacyJavaScriptObject.
+  expect(window is JavaScriptObject, true);
+  runtimeIsAndAs<JavaScriptObject>(window, true);
+  runtimeIsAndAs<JavaScriptObject>(windowDynamic, true);
+  javaScriptObject = jsObj as JavaScriptObject;
+  expect(javaScriptObject is Window, false);
+  runtimeIsAndAs<Window>(javaScriptObject, false);
+
+  expect(window is LegacyJavaScriptObject, false);
+  runtimeIsAndAs<LegacyJavaScriptObject>(window, false);
+  runtimeIsAndAs<LegacyJavaScriptObject>(windowDynamic, false);
+  var legacyJavaScriptObject = jsObj as LegacyJavaScriptObject;
+  expect(legacyJavaScriptObject is Window, false);
+  runtimeIsAndAs<Window>(legacyJavaScriptObject, false);
+
+  // Non-web Native classes like those in `dart:typed_data` are not subclasses
+  // of JavaScriptObject.
   expect(arrayBuffer is JavaScriptObject, false);
   runtimeIsAndAs<JavaScriptObject>(arrayBuffer, false);
+  runtimeIsAndAs<JavaScriptObject>(arrayBufferDynamic, false);
   expect(javaScriptObject is ByteBuffer, false);
   runtimeIsAndAs<ByteBuffer>(javaScriptObject, false);
 
-  // Dynamic native objects are intercepted and cannot be casted to
-  // JavaScriptObject.
-  runtimeIsAndAs<JavaScriptObject>(arrayBufferDynamic, false);
-
   // Make sure `Object` methods work with JavaScriptObject like they do with JS
   // interop objects.
-  expect(anonymousObj == javaScriptObject, true);
+  expect(javaScriptObject == jsObj, true);
   expect(javaScriptObject.hashCode, isNotNull);
   expect(javaScriptObject.toString, isNotNull);
   expect(javaScriptObject.noSuchMethod, isNotNull);
diff --git a/tests/web_2/internal/rti/js_interop_subtype_test.dart b/tests/web_2/internal/rti/js_interop_subtype_test.dart
index 66010da..ffcb31c 100644
--- a/tests/web_2/internal/rti/js_interop_subtype_test.dart
+++ b/tests/web_2/internal/rti/js_interop_subtype_test.dart
@@ -17,6 +17,6 @@
   eval(r'''
       function JSClass() {}
       ''');
-  Expect.type<JavaScriptObject>(JSClass());
-  Expect.type<List<JavaScriptObject>>(<JSClass>[]);
+  Expect.type<LegacyJavaScriptObject>(JSClass());
+  Expect.type<List<LegacyJavaScriptObject>>(<JSClass>[]);
 }
diff --git a/tests/web_2/native/error_safeToString_test.dart b/tests/web_2/native/error_safeToString_test.dart
index cc9acbc..c4d9df0 100644
--- a/tests/web_2/native/error_safeToString_test.dart
+++ b/tests/web_2/native/error_safeToString_test.dart
@@ -9,7 +9,7 @@
 import 'dart:_interceptors'
     show
         Interceptor,
-        JavaScriptObject,
+        LegacyJavaScriptObject,
         PlainJavaScriptObject,
         UnknownJavaScriptObject;
 
diff --git a/tests/web_2/native/jsobject_test.dart b/tests/web_2/native/jsobject_test.dart
index 5b8ed68..3631f85 100644
--- a/tests/web_2/native/jsobject_test.dart
+++ b/tests/web_2/native/jsobject_test.dart
@@ -10,7 +10,7 @@
     show
         JSObject, // The interface, which may be re-exported by a
         // js-interop library.
-        JavaScriptObject, //   The interceptor abstract class.
+        LegacyJavaScriptObject, //   The interceptor abstract class.
         PlainJavaScriptObject, //     The interceptor concrete class.
         UnknownJavaScriptObject, //     The interceptor concrete class.
         Interceptor;
@@ -49,21 +49,21 @@
 static_test() {
   var x = makeA();
   Expect.isTrue(x is JSObject);
-  Expect.isTrue(x is JavaScriptObject);
+  Expect.isTrue(x is LegacyJavaScriptObject);
   Expect.isTrue(x is PlainJavaScriptObject);
   Expect.isTrue(x is! UnknownJavaScriptObject);
   Expect.equals(JSObject, x.runtimeType);
 
   x = makeB();
   Expect.isTrue(x is JSObject);
-  Expect.isTrue(x is JavaScriptObject);
+  Expect.isTrue(x is LegacyJavaScriptObject);
   Expect.isTrue(x is! PlainJavaScriptObject);
   Expect.isTrue(x is UnknownJavaScriptObject);
   Expect.equals(JSObject, x.runtimeType);
 
   x = makeQ();
   Expect.isFalse(x is JSObject);
-  Expect.isFalse(x is JavaScriptObject);
+  Expect.isFalse(x is LegacyJavaScriptObject);
   Expect.isFalse(x is PlainJavaScriptObject);
   Expect.isFalse(x is UnknownJavaScriptObject);
   Expect.isFalse(x.runtimeType == JSObject);
@@ -73,27 +73,27 @@
 dynamic_test() {
   var x = makeA();
   var isJSObject = new Is<JSObject>().check;
-  var isJavaScriptObject = new Is<JavaScriptObject>().check;
+  var isLegacyJavaScriptObject = new Is<LegacyJavaScriptObject>().check;
   var isPlainJavaScriptObject = new Is<PlainJavaScriptObject>().check;
   var isUnknownJavaScriptObject = new Is<UnknownJavaScriptObject>().check;
   var isQ = new Is<Q>().check;
 
   Expect.isTrue(isJSObject(x));
-  Expect.isTrue(isJavaScriptObject(x));
+  Expect.isTrue(isLegacyJavaScriptObject(x));
   Expect.isTrue(isPlainJavaScriptObject(x));
   Expect.isTrue(!isUnknownJavaScriptObject(x));
   Expect.equals(JSObject, x.runtimeType);
 
   x = makeB();
   Expect.isTrue(isJSObject(x));
-  Expect.isTrue(isJavaScriptObject(x));
+  Expect.isTrue(isLegacyJavaScriptObject(x));
   Expect.isTrue(!isPlainJavaScriptObject(x));
   Expect.isTrue(isUnknownJavaScriptObject(x));
   Expect.equals(JSObject, x.runtimeType);
 
   x = makeQ();
   Expect.isFalse(isJSObject(x));
-  Expect.isFalse(isJavaScriptObject(x));
+  Expect.isFalse(isLegacyJavaScriptObject(x));
   Expect.isFalse(isPlainJavaScriptObject(x));
   Expect.isFalse(isUnknownJavaScriptObject(x));
   Expect.isTrue(isQ(x));
diff --git a/tests/web_2/native/static_interop_erasure/factory_stub_test.dart b/tests/web_2/native/static_interop_erasure/factory_stub_test.dart
new file mode 100644
index 0000000..8aba8f4
--- /dev/null
+++ b/tests/web_2/native/static_interop_erasure/factory_stub_test.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart = 2.7
+
+// Test that factory methods with bodies are stubbed correctly in static interop
+// type erasure.
+
+@JS()
+library factory_stub_test;
+
+import 'dart:_interceptors' show JavaScriptObject;
+
+import 'package:js/js.dart';
+
+import '../native_testing.dart';
+import '../native_testing.dart' as native_testing;
+
+NativeClass makeNativeClass() native;
+
+@Native('NativeClass')
+class NativeClass extends JavaScriptObject {
+  factory NativeClass() => makeNativeClass();
+}
+
+@JS('NativeClass')
+@staticInterop
+class StaticNativeClass {
+  external StaticNativeClass();
+  factory StaticNativeClass.redirectingFactory() = StaticNativeClass;
+  factory StaticNativeClass.simpleFactory() => StaticNativeClass();
+  factory StaticNativeClass.factoryWithParam(
+          StaticNativeClass staticNativeClass) =>
+      staticNativeClass;
+  // This and `StaticNativeClassCopy.nestedFactory` exist to ensure that we
+  // cover the case where invocations on factories are visible before their
+  // declarations in the AST. This will test whether we correctly create the
+  // stub even if we haven't visited the declaration yet.
+  factory StaticNativeClass.nestedFactory() {
+    StaticNativeClassCopy.nestedFactory();
+    return StaticNativeClass();
+  }
+}
+
+@JS('NativeClass')
+@staticInterop
+class StaticNativeClassCopy {
+  external StaticNativeClassCopy();
+  factory StaticNativeClassCopy.nestedFactory() {
+    StaticNativeClass.simpleFactory();
+    return StaticNativeClassCopy();
+  }
+}
+
+void main() {
+  nativeTesting();
+  native_testing.JS('', r'''
+    (function(){
+      function NativeClass() {}
+      self.NativeClass = NativeClass;
+      self.makeNativeClass = function(){return new NativeClass()};
+      self.nativeConstructor(NativeClass);
+    })()
+  ''');
+  applyTestExtensions(['NativeClass']);
+
+  // Make the Native class live.
+  NativeClass();
+  // Invoke factories and ensure they're typed correctly through assignment.
+  StaticNativeClass staticNativeClass = StaticNativeClass.redirectingFactory();
+  staticNativeClass = StaticNativeClass.simpleFactory();
+  staticNativeClass = StaticNativeClass.factoryWithParam(staticNativeClass);
+  staticNativeClass = StaticNativeClass.nestedFactory();
+}
diff --git a/tests/web_2/native/static_interop_erasure/type_test.dart b/tests/web_2/native/static_interop_erasure/type_test.dart
new file mode 100644
index 0000000..5d85ebb
--- /dev/null
+++ b/tests/web_2/native/static_interop_erasure/type_test.dart
@@ -0,0 +1,226 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart = 2.7
+
+// Test that the type and subtyping relationships between static interop,
+// non-static interop, and Native classes are well-formed.
+
+@JS()
+library type_test;
+
+import 'dart:_interceptors' show JavaScriptObject;
+
+import 'package:expect/minitest.dart';
+import 'package:js/js.dart';
+
+import '../native_testing.dart';
+import '../native_testing.dart' as native_testing;
+
+NativeClass makeNativeClass() native;
+
+@Native('NativeClass')
+class NativeClass extends JavaScriptObject {
+  factory NativeClass() => makeNativeClass();
+}
+
+@JS('NativeClass')
+@staticInterop
+class StaticNativeClass {
+  external StaticNativeClass();
+}
+
+@JS()
+class JSClass {
+  external JSClass();
+}
+
+@JS('JSClass')
+@staticInterop
+class StaticJSClass {
+  external StaticJSClass();
+}
+
+@JS()
+@anonymous
+class AnonymousClass {
+  external factory();
+}
+
+@JS()
+@staticInterop
+class GenericStaticJSClass<T> {}
+
+NativeClass returnNativeClass() => throw '';
+
+StaticNativeClass returnStaticNativeClass() => throw '';
+
+JSClass returnJSClass() => throw '';
+
+StaticJSClass returnStaticJSClass() => throw '';
+
+AnonymousClass returnAnonymousClass() => throw '';
+
+GenericStaticJSClass<int> returnGenericStaticJSClassInt() => throw '';
+
+void main() {
+  nativeTesting();
+  native_testing.JS('', r'''
+    (function(){
+      function NativeClass() {}
+      self.NativeClass = NativeClass;
+      self.makeNativeClass = function(){return new NativeClass()};
+      self.nativeConstructor(NativeClass);
+      function JSClass() {}
+      self.JSClass = JSClass;
+    })()
+  ''');
+  applyTestExtensions(['NativeClass']);
+
+  var nativeClass = NativeClass();
+  var staticNativeClass = StaticNativeClass();
+  var jsClass = JSClass();
+  var staticJsClass = StaticJSClass();
+  var anonymousClass = AnonymousClass();
+
+  // Native objects can be interop'd with static interop classes.
+  expect(nativeClass is StaticNativeClass, true);
+  expect(confuse(nativeClass) is StaticNativeClass, true);
+  expect(() => nativeClass as StaticNativeClass, returnsNormally);
+
+  expect(staticNativeClass is NativeClass, true);
+  expect(confuse(staticNativeClass) is NativeClass, true);
+  expect(() => staticNativeClass as NativeClass, returnsNormally);
+
+  // Likewise, non-native JS objects can be interop'd with static interop
+  // classes as well.
+  expect(jsClass is StaticJSClass, true);
+  expect(confuse(jsClass) is StaticJSClass, true);
+  expect(() => jsClass as StaticJSClass, returnsNormally);
+
+  expect(staticJsClass is JSClass, true);
+  expect(confuse(staticJsClass) is JSClass, true);
+  expect(() => staticJsClass as JSClass, returnsNormally);
+
+  expect(anonymousClass is StaticJSClass, true);
+  expect(confuse(anonymousClass) is StaticJSClass, true);
+  expect(() => anonymousClass as StaticJSClass, returnsNormally);
+
+  expect(staticJsClass is AnonymousClass, true);
+  expect(confuse(staticJsClass) is AnonymousClass, true);
+  expect(() => staticJsClass as AnonymousClass, returnsNormally);
+
+  // With erasure, all static interop classes become the same type, so you can
+  // cast either interop or native objects to them regardless of the underlying
+  // class.
+  expect(staticNativeClass is StaticJSClass, true);
+  expect(confuse(staticNativeClass) is StaticJSClass, true);
+  expect(() => staticNativeClass as StaticJSClass, returnsNormally);
+
+  expect(staticJsClass is StaticNativeClass, true);
+  expect(confuse(staticJsClass) is StaticNativeClass, true);
+  expect(() => staticJsClass as StaticNativeClass, returnsNormally);
+
+  expect(nativeClass is StaticJSClass, true);
+  expect(confuse(nativeClass) is StaticJSClass, true);
+  expect(() => nativeClass as StaticJSClass, returnsNormally);
+
+  expect(jsClass is StaticNativeClass, true);
+  expect(confuse(jsClass) is StaticNativeClass, true);
+  expect(() => jsClass as StaticNativeClass, returnsNormally);
+
+  expect(anonymousClass is StaticNativeClass, true);
+  expect(confuse(anonymousClass) is StaticNativeClass, true);
+  expect(() => anonymousClass as StaticNativeClass, returnsNormally);
+
+  // You cannot, however, always cast from a static interop type to an interop
+  // type or a native type. That will depend on whether the object is an interop
+  // object or a native object.
+  expect(staticNativeClass is JSClass, false);
+  expect(confuse(staticNativeClass) is JSClass, false);
+  expect(() => staticNativeClass as JSClass, throws);
+
+  expect(staticNativeClass is AnonymousClass, false);
+  expect(confuse(staticNativeClass) is AnonymousClass, false);
+  expect(() => staticNativeClass as AnonymousClass, throws);
+
+  expect(staticJsClass is NativeClass, false);
+  expect(confuse(staticJsClass) is NativeClass, false);
+  expect(() => staticJsClass as NativeClass, throws);
+
+  // Subtyping rules.
+
+  // Note that erasure ignores all static class type parameters so this
+  // comparison becomes
+  // `JavaScriptObject Function() is JavaScriptObject Function()`. This behavior
+  // is similar to non-static interop classes.
+  expect(
+      returnGenericStaticJSClassInt is GenericStaticJSClass<String> Function(),
+      true);
+  expect(
+      confuse(returnGenericStaticJSClassInt) is GenericStaticJSClass<String>
+          Function(),
+      true);
+  expect(
+      () => returnGenericStaticJSClassInt as GenericStaticJSClass<String>
+          Function(),
+      returnsNormally);
+
+  // static interop class A <: static interop class A
+  expect(returnStaticNativeClass is StaticNativeClass Function(), true);
+  expect(
+      confuse(returnStaticNativeClass) is StaticNativeClass Function(), true);
+  expect(returnStaticJSClass is StaticJSClass Function(), true);
+  expect(confuse(returnStaticJSClass) is StaticJSClass Function(), true);
+
+  // static interop class A <: static interop class B
+  expect(returnStaticNativeClass is StaticJSClass Function(), true);
+  expect(confuse(returnStaticNativeClass) is StaticJSClass Function(), true);
+  expect(returnStaticJSClass is StaticNativeClass Function(), true);
+  expect(confuse(returnStaticJSClass) is StaticNativeClass Function(), true);
+
+  // static interop class !<: native class
+  expect(returnStaticNativeClass is NativeClass Function(), false);
+  expect(confuse(returnStaticNativeClass) is NativeClass Function(), false);
+  expect(returnStaticJSClass is NativeClass Function(), false);
+  expect(confuse(returnStaticJSClass) is NativeClass Function(), false);
+
+  // static interop class !<: package:js class
+  expect(returnStaticNativeClass is JSClass Function(), false);
+  expect(confuse(returnStaticNativeClass) is JSClass Function(), false);
+  expect(returnStaticJSClass is JSClass Function(), false);
+  expect(confuse(returnStaticJSClass) is JSClass Function(), false);
+
+  // static interop class !<: anonymous class
+  expect(returnStaticNativeClass is AnonymousClass Function(), false);
+  expect(confuse(returnStaticNativeClass) is AnonymousClass Function(), false);
+  expect(returnStaticJSClass is AnonymousClass Function(), false);
+  expect(confuse(returnStaticJSClass) is AnonymousClass Function(), false);
+
+  // native class <: static interop class
+  expect(returnNativeClass is StaticJSClass Function(), true);
+  expect(confuse(returnNativeClass) is StaticJSClass Function(), true);
+  expect(returnNativeClass is StaticNativeClass Function(), true);
+  expect(confuse(returnNativeClass) is StaticNativeClass Function(), true);
+
+  // package:js class <: static interop class
+  // TODO(46456): The runtime check using `confuse` does not fail, whereas the
+  // compile-time check does on dart2js.
+  // expect(returnJSClass is StaticJSClass Function(), true);
+  expect(confuse(returnJSClass) is StaticJSClass Function(), true);
+  // TODO(46456): The runtime check using `confuse` does not fail, whereas the
+  // compile-time check does on dart2js.
+  // expect(returnJSClass is StaticNativeClass Function(), true);
+  expect(confuse(returnJSClass) is StaticNativeClass Function(), true);
+
+  // anonymous class <: static interop class
+  // TODO(46456): The runtime check using `confuse` does not fail, whereas the
+  // compile-time check does on dart2js.
+  // expect(returnAnonymousClass is StaticJSClass Function(), true);
+  expect(confuse(returnAnonymousClass) is StaticJSClass Function(), true);
+  // TODO(46456): The runtime check using `confuse` does not fail, whereas the
+  // compile-time check does on dart2js.
+  // expect(returnAnonymousClass is StaticNativeClass Function(), true);
+  expect(confuse(returnAnonymousClass) is StaticNativeClass Function(), true);
+}
diff --git a/tests/web_2/native/static_interop_erasure/use_erased_type_members_test.dart b/tests/web_2/native/static_interop_erasure/use_erased_type_members_test.dart
new file mode 100644
index 0000000..22ad0c3
--- /dev/null
+++ b/tests/web_2/native/static_interop_erasure/use_erased_type_members_test.dart
@@ -0,0 +1,148 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart = 2.7
+
+// Test that a static interop class can be used in place of a Native class and
+// its static members work as expected post-erasure.
+
+@JS()
+library use_erased_type_members_test;
+
+import 'dart:_interceptors' show JavaScriptObject;
+
+import 'package:expect/minitest.dart';
+import 'package:js/js.dart';
+
+import '../native_testing.dart';
+import '../native_testing.dart' as native_testing;
+
+NativeClass makeNativeClass() native;
+
+@Native('NativeClass')
+class NativeClass extends JavaScriptObject {
+  factory NativeClass() => makeNativeClass();
+}
+
+@JS()
+@staticInterop
+class Parent {}
+
+extension ParentExtension on Parent {
+  external String get parentExternalGetSet;
+  external set parentExternalGetSet(String val);
+  external String parentExternalMethod();
+
+  String get parentGetSet => this.parentExternalGetSet;
+  set parentGetSet(String val) => this.parentExternalGetSet = val;
+  String parentMethod() => 'parentMethod';
+}
+
+@JS()
+@staticInterop
+class Interface {}
+
+extension InterfaceExtension on Interface {
+  external String get interfaceExternalGetSet;
+  external set interfaceExternalGetSet(String val);
+  external String interfaceExternalMethod();
+
+  String get interfaceGetSet => this.interfaceExternalGetSet;
+  set interfaceGetSet(String val) => this.interfaceExternalGetSet = val;
+  String interfaceMethod() => 'interfaceMethod';
+}
+
+@JS('NativeClass')
+@staticInterop
+class StaticJSClass extends Parent implements Interface {
+  external StaticJSClass();
+  external StaticJSClass.namedConstructor();
+  external factory StaticJSClass.externalFactory();
+  factory StaticJSClass.redirectingFactory() = StaticJSClass;
+
+  external static String get externalStaticGetSet;
+  external static set externalStaticGetSet(String val);
+  external static String externalStaticMethod();
+}
+
+extension StaticJSClassExtension on StaticJSClass {
+  external String get externalGetSet;
+  external set externalGetSet(String val);
+  external String externalMethod();
+
+  String get getSet => this.externalGetSet;
+  set getSet(String val) => this.externalGetSet = val;
+  String method() => 'method';
+}
+
+void main() {
+  nativeTesting();
+  native_testing.JS('', r'''
+    (function(){
+      function NativeClass() {
+        this.externalGetSet = '';
+        this.externalMethod = function() { return 'externalMethod'; };
+
+        this.parentExternalGetSet = '';
+        this.parentExternalMethod = function() {
+          return 'parentExternalMethod';
+        };
+
+        this.interfaceExternalGetSet = '';
+        this.interfaceExternalMethod = function() {
+          return 'interfaceExternalMethod';
+        };
+      }
+      NativeClass.externalStaticField = 'externalStaticField';
+      NativeClass.externalStaticGetSet = NativeClass.externalStaticField;
+      NativeClass.externalStaticMethod = function() {
+        return 'externalStaticMethod';
+      };
+      self.NativeClass = NativeClass;
+      self.makeNativeClass = function(){return new NativeClass()};
+      self.nativeConstructor(NativeClass);
+    })()
+  ''');
+  applyTestExtensions(['NativeClass']);
+
+  // NativeClass needs to be live, so it can be correctly intercepted.
+  NativeClass();
+  // Invoke constructors and ensure they're typed correctly.
+  StaticJSClass staticJs = StaticJSClass();
+  staticJs = StaticJSClass.namedConstructor();
+  staticJs = StaticJSClass.externalFactory();
+  staticJs = StaticJSClass.redirectingFactory();
+
+  // Invoke external static members.
+  StaticJSClass.externalStaticGetSet = 'externalStaticGetSet';
+  expect(StaticJSClass.externalStaticGetSet, 'externalStaticGetSet');
+  expect(StaticJSClass.externalStaticMethod(), 'externalStaticMethod');
+
+  // Use extension members.
+  staticJs.externalGetSet = 'externalGetSet';
+  expect(staticJs.externalGetSet, 'externalGetSet');
+  expect(staticJs.externalMethod(), 'externalMethod');
+
+  staticJs.getSet = 'getSet';
+  expect(staticJs.getSet, 'getSet');
+  expect(staticJs.method(), 'method');
+
+  // Use parent extension members.
+  staticJs.parentExternalGetSet = 'parentExternalGetSet';
+  expect(staticJs.parentExternalGetSet, 'parentExternalGetSet');
+  expect(staticJs.parentExternalMethod(), 'parentExternalMethod');
+
+  staticJs.parentGetSet = 'parentGetSet';
+  expect(staticJs.parentGetSet, 'parentGetSet');
+  expect(staticJs.parentMethod(), 'parentMethod');
+
+  // Use interface extension members.
+  staticJs.interfaceExternalGetSet = 'interfaceExternalGetSet';
+  expect(staticJs.interfaceExternalGetSet, 'interfaceExternalGetSet');
+  expect(staticJs.interfaceExternalMethod(), 'interfaceExternalMethod');
+
+  staticJs.interfaceGetSet = 'interfaceGetSet';
+  expect(staticJs.interfaceGetSet, 'interfaceGetSet');
+  expect(staticJs.interfaceMethod(), 'interfaceMethod');
+}
diff --git a/tools/VERSION b/tools/VERSION
index 42c478b..4958d12 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 16
 PATCH 0
-PRERELEASE 99
+PRERELEASE 100
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 9fa35dc..63d913e 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -732,7 +732,7 @@
         if mixins:
             mixins_str = ' with ' + ', '.join(mixins)
             if not base_class:
-                base_class = 'Interceptor'
+                base_class = 'JavaScriptObject'
             elif (base_class == 'NativeFieldWrapperClass2' and
                   self._options.dart_js_interop and
                   not (isinstance(self._backend, Dart2JSBackend))):
@@ -1831,7 +1831,7 @@
         pass
 
     def RootClassName(self):
-        return 'Interceptor'
+        return 'JavaScriptObject'
 
     def OmitOperationOverrides(self):
         return True
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index b3dc526..c185ef7 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -45,7 +45,7 @@
     findDispatchTagForInterceptorClass, setNativeSubclassDispatchRecord,
     makeLeafDispatchRecord, registerGlobalObject, applyExtension;
 import 'dart:_interceptors' show
-    Interceptor, JavaScriptFunction, JSExtendableArray, JSUInt31,
+    JavaScriptObject, JavaScriptFunction, JSExtendableArray, JSUInt31,
     findInterceptorConstructorForType,
     findConstructorForNativeSubclassType,
     getNativeInterceptor,
diff --git a/tools/dom/templates/html/dart2js/indexed_db_dart2js.darttemplate b/tools/dom/templates/html/dart2js/indexed_db_dart2js.darttemplate
index 8373820..2bfbeeb 100644
--- a/tools/dom/templates/html/dart2js/indexed_db_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/indexed_db_dart2js.darttemplate
@@ -83,7 +83,7 @@
 import 'dart:typed_data';
 import 'dart:_js_helper' show Creates, Returns, JSName, Native;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+import 'dart:_interceptors' show JavaScriptObject, JSExtendableArray;
 
 import 'dart:_js_helper' show convertDartClosureToJS;
 
diff --git a/tools/dom/templates/html/dart2js/svg_dart2js.darttemplate b/tools/dom/templates/html/dart2js/svg_dart2js.darttemplate
index e2f72ee..c7f153a 100644
--- a/tools/dom/templates/html/dart2js/svg_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/svg_dart2js.darttemplate
@@ -21,7 +21,7 @@
 import 'dart:html_common';
 import 'dart:_js_helper' show Creates, Returns, JSName, Native;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor;
+import 'dart:_interceptors' show JavaScriptObject;
 
 part '$AUXILIARY_DIR/shared_SVGFactoryProviders.dart';
 
diff --git a/tools/dom/templates/html/dart2js/web_audio_dart2js.darttemplate b/tools/dom/templates/html/dart2js/web_audio_dart2js.darttemplate
index 31437b3..44c468f 100644
--- a/tools/dom/templates/html/dart2js/web_audio_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/web_audio_dart2js.darttemplate
@@ -20,6 +20,6 @@
     Creates, JavaScriptIndexingBehavior, JSName, Native, Returns,
     convertDartClosureToJS;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor;
+import 'dart:_interceptors' show JavaScriptObject;
 
 $!GENERATED_DART_FILES
diff --git a/tools/dom/templates/html/dart2js/web_gl_dart2js.darttemplate b/tools/dom/templates/html/dart2js/web_gl_dart2js.darttemplate
index 8780f3a..5b2fc8cf 100644
--- a/tools/dom/templates/html/dart2js/web_gl_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/web_gl_dart2js.darttemplate
@@ -18,6 +18,6 @@
 import 'dart:typed_data';
 import 'dart:_js_helper' show Creates, JSName, Native, Returns, convertDartClosureToJS;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor, JSExtendableArray;
+import 'dart:_interceptors' show JavaScriptObject, JSExtendableArray;
 
 $!GENERATED_DART_FILES
diff --git a/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate b/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate
index 8877f95..9c25d0a 100644
--- a/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate
@@ -26,6 +26,6 @@
 import 'dart:_js_helper' show applyExtension, convertDartClosureToJS, Creates,
     JSName, Native, JavaScriptIndexingBehavior, Returns;
 import 'dart:_foreign_helper' show JS;
-import 'dart:_interceptors' show Interceptor;
+import 'dart:_interceptors' show JavaScriptObject;
 
 $!GENERATED_DART_FILES