Update lints, test JS & Wasm (#116)

* Update lints, test JS & Wasm

* more bumps

* require dart 3.4
diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml
index 0978fe2..c8e65b6 100644
--- a/.github/workflows/test-package.yml
+++ b/.github/workflows/test-package.yml
@@ -47,7 +47,7 @@
       matrix:
         # Add macos-latest and/or windows-latest if relevant for this package.
         os: [ubuntu-latest]
-        sdk: [2.19.0, dev]
+        sdk: [3.4, dev]
     steps:
       - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
       - uses: dart-lang/setup-dart@f0ead981b4d9a35b37f30d36160575d60931ec30
@@ -59,3 +59,6 @@
       - name: Run VM tests
         run: dart test --platform vm
         if: always() && steps.install.outcome == 'success'
+      - name: Run browser tests
+        run: dart test --platform chrome --compiler dart2wasm,dart2js
+        if: always() && steps.install.outcome == 'success'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 751a8f8..aec8201 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
-## 3.0.3-dev
+## 3.0.3-wip
 
-* Require Dart 2.19
+* Require Dart 3.4
 
 ## 3.0.2
 
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 3339609..873cf41 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -12,4 +12,3 @@
     - avoid_unused_constructor_parameters
     - cancel_subscriptions
     - package_api_docs
-    - test_types_in_equals
diff --git a/lib/error_code.dart b/lib/error_code.dart
index 14e0543..5f90791 100644
--- a/lib/error_code.dart
+++ b/lib/error_code.dart
@@ -4,7 +4,9 @@
 
 // ignore_for_file: constant_identifier_names
 
-/// Error codes defined in the [JSON-RPC 2.0 specificiation][spec].
+import 'src/exception.dart';
+
+/// Error codes defined in the [JSON-RPC 2.0 specification][spec].
 ///
 /// These codes are generally used for protocol-level communication. Most of
 /// them shouldn't be used by the application. Those that should have
@@ -38,20 +40,12 @@
 /// Returns a human-readable name for [errorCode] if it's one specified by the
 /// JSON-RPC 2.0 spec.
 ///
-/// If [errorCode] isn't defined in the JSON-RPC 2.0 spec, returns null.
-String? name(int errorCode) {
-  switch (errorCode) {
-    case PARSE_ERROR:
-      return 'parse error';
-    case INVALID_REQUEST:
-      return 'invalid request';
-    case METHOD_NOT_FOUND:
-      return 'method not found';
-    case INVALID_PARAMS:
-      return 'invalid parameters';
-    case INTERNAL_ERROR:
-      return 'internal error';
-    default:
-      return null;
-  }
-}
+/// If [errorCode] isn't defined in the JSON-RPC 2.0 spec, returns `null`.
+String? name(int errorCode) => switch (errorCode) {
+      PARSE_ERROR => 'parse error',
+      INVALID_REQUEST => 'invalid request',
+      METHOD_NOT_FOUND => 'method not found',
+      INVALID_PARAMS => 'invalid parameters',
+      INTERNAL_ERROR => 'internal error',
+      _ => null
+    };
diff --git a/lib/src/client.dart b/lib/src/client.dart
index a3637dd..182f945 100644
--- a/lib/src/client.dart
+++ b/lib/src/client.dart
@@ -47,19 +47,19 @@
 
   /// Creates a [Client] that communicates over [channel].
   ///
-  /// Note that the client won't begin listening to [responses] until
+  /// Note that the client won't begin listening to [channel] until
   /// [Client.listen] is called.
   Client(StreamChannel<String> channel)
       : this.withoutJson(
             jsonDocument.bind(channel).transformStream(ignoreFormatExceptions));
 
   /// Creates a [Client] that communicates using decoded messages over
-  /// [channel].
+  /// [_channel].
   ///
   /// Unlike [Client.new], this doesn't read or write JSON strings. Instead, it
   /// reads and writes decoded maps or lists.
   ///
-  /// Note that the client won't begin listening to [responses] until
+  /// Note that the client won't begin listening to [_channel] until
   /// [Client.listen] is called.
   Client.withoutJson(this._channel) {
     done.whenComplete(() {
@@ -80,7 +80,8 @@
   ///
   /// [listen] may only be called once.
   Future listen() {
-    _channel.stream.listen(_handleResponse, onError: (error, stackTrace) {
+    _channel.stream.listen(_handleResponse,
+        onError: (Object error, StackTrace stackTrace) {
       _done.completeError(error, stackTrace);
       _channel.sink.close();
     }, onDone: () {
@@ -113,11 +114,11 @@
   ///
   /// Throws a [StateError] if the client is closed while the request is in
   /// flight, or if the client is closed when this method is called.
-  Future sendRequest(String method, [Object? parameters]) {
+  Future<Object?> sendRequest(String method, [Object? parameters]) {
     var id = _id++;
     _send(method, parameters, id);
 
-    var completer = Completer.sync();
+    var completer = Completer<Object?>.sync();
     _pendingRequests[id] = _Request(method, completer, Chain.current());
     return completer.future;
   }
@@ -141,7 +142,7 @@
   ///
   /// Sends a request to invoke [method] with [parameters]. If [id] is given,
   /// the request uses that id.
-  void _send(String method, parameters, [int? id]) {
+  void _send(String method, Object? parameters, [int? id]) {
     if (parameters is Iterable) parameters = parameters.toList();
     if (parameters is! Map && parameters is! List && parameters != null) {
       throw ArgumentError('Only maps and lists may be used as JSON-RPC '
@@ -172,7 +173,7 @@
   /// If this is called in the context of another [withBatch] call, it just
   /// invokes [callback] without creating another batch. This means that
   /// responses are batched until the first batch ends.
-  void withBatch(Function() callback) {
+  void withBatch(FutureOr<void> Function() callback) {
     if (_batch != null) {
       callback();
       return;
@@ -186,7 +187,7 @@
   }
 
   /// Handles a decoded response from the server.
-  void _handleResponse(response) {
+  void _handleResponse(Object? response) {
     if (response is List) {
       response.forEach(_handleSingleResponse);
     } else {
@@ -196,8 +197,9 @@
 
   /// Handles a decoded response from the server after batches have been
   /// resolved.
-  void _handleSingleResponse(response) {
-    if (!_isResponseValid(response)) return;
+  void _handleSingleResponse(Object? response_) {
+    if (!_isResponseValid(response_)) return;
+    final response = response_ as Map;
     var id = response['id'];
     id = (id is String) ? int.parse(id) : id;
     var request = _pendingRequests.remove(id)!;
@@ -212,7 +214,7 @@
   }
 
   /// Determines whether the server's response is valid per the spec.
-  bool _isResponseValid(response) {
+  bool _isResponseValid(Object? response) {
     if (response is! Map) return false;
     if (response['jsonrpc'] != '2.0') return false;
     var id = response['id'];
diff --git a/lib/src/exception.dart b/lib/src/exception.dart
index 3b9c0ec..906a053 100644
--- a/lib/src/exception.dart
+++ b/lib/src/exception.dart
@@ -46,8 +46,10 @@
   Map<String, dynamic> serialize(Object? request) {
     dynamic modifiedData;
     if (data is Map && !(data as Map).containsKey('request')) {
-      modifiedData = Map.from(data as Map);
-      modifiedData['request'] = request;
+      modifiedData = {
+        ...data as Map,
+        'request': request,
+      };
     } else if (data == null) {
       modifiedData = {'request': request};
     } else {
diff --git a/lib/src/parameters.dart b/lib/src/parameters.dart
index f747b98..0a18882 100644
--- a/lib/src/parameters.dart
+++ b/lib/src/parameters.dart
@@ -109,8 +109,8 @@
   // The parent parameters, used to construct [_path].
   final Parameters _parent;
 
-  /// The key used to access [this], used to construct [_path].
-  final dynamic _key;
+  /// The key used to access `this`, used to construct [_path].
+  final Object _key;
 
   /// A human-readable representation of the path of getters used to get this.
   ///
@@ -130,20 +130,22 @@
       return _key is int ? (_key + 1).toString() : jsonEncode(_key);
     }
 
-    String quoteKey(key) {
+    String quoteKey(String key) {
       if (key.contains(RegExp(r'[^a-zA-Z0-9_-]'))) return jsonEncode(key);
       return key;
     }
 
-    String computePath(params) {
+    String computePath(Parameter params) {
       if (params._parent is! Parameter) {
-        return params._key is int ? '[${params._key}]' : quoteKey(params._key);
+        return params._key is int
+            ? '[${params._key}]'
+            : quoteKey(params._key as String);
       }
 
       var path = computePath(params._parent);
       return params._key is int
           ? '$path[${params._key}]'
-          : '$path.${quoteKey(params._key)}';
+          : '$path.${quoteKey(params._key as String)}';
     }
 
     return computePath(this);
@@ -152,8 +154,7 @@
   /// Whether this parameter exists.
   bool get exists => true;
 
-  Parameter._(String method, value, this._parent, this._key)
-      : super(method, value);
+  Parameter._(super.method, super.value, this._parent, this._key);
 
   /// Returns [value], or [defaultValue] if this parameter wasn't passed.
   dynamic valueOr(Object? defaultValue) => value;
@@ -260,8 +261,7 @@
   /// If [value] doesn't exist, this returns [defaultValue].
   Uri asUriOr(Uri defaultValue) => asUri;
 
-  /// Get a parameter named [named] that matches [test], or the value of calling
-  /// [orElse].
+  /// Get a parameter named [type] that matches [test].
   ///
   /// [type] is used for the error message. It should begin with an indefinite
   /// article.
@@ -271,7 +271,7 @@
         '"$method" must be $type, but was ${jsonEncode(value)}.');
   }
 
-  dynamic _getParsed(String description, Function(String) parse) {
+  dynamic _getParsed(String description, void Function(String) parse) {
     var string = asString;
     try {
       return parse(string);
@@ -316,7 +316,7 @@
   @override
   bool get exists => false;
 
-  _MissingParameter(String method, Parameters parent, key)
+  _MissingParameter(String method, Parameters parent, Object key)
       : super._(method, null, parent, key);
 
   @override
diff --git a/lib/src/peer.dart b/lib/src/peer.dart
index 002af31..677b6e1 100644
--- a/lib/src/peer.dart
+++ b/lib/src/peer.dart
@@ -29,11 +29,11 @@
 
   /// A stream controller that forwards incoming messages to [_server] if
   /// they're requests.
-  final _serverIncomingForwarder = StreamController(sync: true);
+  final _serverIncomingForwarder = StreamController<Object?>(sync: true);
 
   /// A stream controller that forwards incoming messages to [_client] if
   /// they're responses.
-  final _clientIncomingForwarder = StreamController(sync: true);
+  final _clientIncomingForwarder = StreamController<Object?>(sync: true);
 
   @override
   late final Future done = Future.wait([_client.done, _server.done]);
@@ -66,12 +66,12 @@
             onUnhandledError: onUnhandledError,
             strictProtocolChecks: strictProtocolChecks);
 
-  /// Creates a [Peer] that communicates using decoded messages over [channel].
+  /// Creates a [Peer] that communicates using decoded messages over [_channel].
   ///
   /// Unlike [Peer.new], this doesn't read or write JSON strings. Instead, it
   /// reads and writes decoded maps or lists.
   ///
-  /// Note that the peer won't begin listening to [channel] until
+  /// Note that the peer won't begin listening to [_channel] until
   /// [Peer.listen] is called.
   ///
   /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
@@ -102,7 +102,7 @@
       _client.sendNotification(method, parameters);
 
   @override
-  void withBatch(Function() callback) => _client.withBatch(callback);
+  void withBatch(void Function() callback) => _client.withBatch(callback);
 
   // Server methods.
 
@@ -111,7 +111,7 @@
       _server.registerMethod(name, callback);
 
   @override
-  void registerFallback(Function(Parameters parameters) callback) =>
+  void registerFallback(void Function(Parameters parameters) callback) =>
       _server.registerFallback(callback);
 
   // Shared methods.
@@ -141,7 +141,7 @@
         // server since it knows how to send error responses.
         _serverIncomingForwarder.add(message);
       }
-    }, onError: (error, stackTrace) {
+    }, onError: (Object error, StackTrace stackTrace) {
       _serverIncomingForwarder.addError(error, stackTrace);
     }, onDone: close);
     return done;
diff --git a/lib/src/server.dart b/lib/src/server.dart
index 14ef02e..2c58b79 100644
--- a/lib/src/server.dart
+++ b/lib/src/server.dart
@@ -21,8 +21,7 @@
 ///
 /// A server exposes methods that are called by requests, to which it provides
 /// responses. Methods can be registered using [registerMethod] and
-/// [registerFallback]. Requests can be handled using [handleRequest] and
-/// [parseRequest].
+/// [registerFallback].
 ///
 /// Note that since requests can arrive asynchronously and methods can run
 /// asynchronously, it's possible for multiple methods to be invoked at the same
@@ -72,7 +71,7 @@
 
   /// Creates a [Server] that communicates over [channel].
   ///
-  /// Note that the server won't begin listening to [requests] until
+  /// Note that the server won't begin listening to [channel] until
   /// [Server.listen] is called.
   ///
   /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
@@ -89,12 +88,12 @@
             strictProtocolChecks: strictProtocolChecks);
 
   /// Creates a [Server] that communicates using decoded messages over
-  /// [channel].
+  /// [_channel].
   ///
   /// Unlike [Server.new], this doesn't read or write JSON strings. Instead, it
   /// reads and writes decoded maps or lists.
   ///
-  /// Note that the server won't begin listening to [requests] until
+  /// Note that the server won't begin listening to [_channel] until
   /// [Server.listen] is called.
   ///
   /// Unhandled exceptions in callbacks will be forwarded to [onUnhandledError].
@@ -113,7 +112,8 @@
   ///
   /// [listen] may only be called once.
   Future listen() {
-    _channel.stream.listen(_handleRequest, onError: (error, stackTrace) {
+    _channel.stream.listen(_handleRequest,
+        onError: (Object error, StackTrace stackTrace) {
       _done.completeError(error, stackTrace);
       _channel.sink.close();
     }, onDone: () {
@@ -160,7 +160,7 @@
   /// completes to a JSON-serializable object. Any errors in [callback] will be
   /// reported to the client as JSON-RPC 2.0 errors. [callback] may send custom
   /// errors by throwing an [RpcException].
-  void registerFallback(Function(Parameters parameters) callback) {
+  void registerFallback(void Function(Parameters parameters) callback) {
     _fallbacks.add(callback);
   }
 
@@ -169,9 +169,8 @@
   /// [request] is expected to be a JSON-serializable object representing a
   /// request sent by a client. This calls the appropriate method or methods for
   /// handling that request and returns a JSON-serializable response, or `null`
-  /// if no response should be sent. [callback] may send custom
-  /// errors by throwing an [RpcException].
-  Future _handleRequest(request) async {
+  /// if no response should be sent.
+  Future _handleRequest(Object? request) async {
     dynamic response;
     if (request is List) {
       if (request.isEmpty) {
@@ -241,7 +240,7 @@
   }
 
   /// Validates that [request] matches the JSON-RPC spec.
-  void _validateRequest(request) {
+  void _validateRequest(Object? request) {
     if (request is! Map) {
       throw RpcException(
           error_code.INVALID_REQUEST,
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index c7cd10f..28bbf21 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -9,7 +9,7 @@
 import '../error_code.dart' as error_code;
 import 'exception.dart';
 
-typedef ZeroArgumentFunction = Function();
+typedef ZeroArgumentFunction = FutureOr Function();
 
 /// A regular expression to match the exception prefix that some exceptions'
 /// [Object.toString] values contain.
@@ -18,7 +18,7 @@
 /// Get a string description of an exception.
 ///
 /// Many exceptions include the exception class name at the beginning of their
-/// [toString], so we remove that if it exists.
+/// `toString`, so we remove that if it exists.
 String getErrorMessage(Object error) =>
     error.toString().replaceFirst(_exceptionPrefix, '');
 
@@ -27,7 +27,7 @@
 ///
 /// This is synchronicity-agnostic relative to [body]. If [body] returns a
 /// [Future], this wil run asynchronously; otherwise it will run synchronously.
-void tryFinally(Function() body, Function() whenComplete) {
+void tryFinally(dynamic Function() body, void Function() whenComplete) {
   dynamic result;
   try {
     result = body();
diff --git a/pubspec.yaml b/pubspec.yaml
index 53f5885..ae3ee94 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,17 +1,17 @@
 name: json_rpc_2
-version: 3.0.3-dev
+version: 3.0.3-wip
 description: >-
   Utilities to write a client or server using the JSON-RPC 2.0 spec.
 repository: https://github.com/dart-lang/json_rpc_2
 
 environment:
-  sdk: ">=2.19.0 <3.0.0"
+  sdk: ^3.4.0
 
 dependencies:
   stack_trace: ^1.10.0
   stream_channel: ^2.1.0
 
 dev_dependencies:
-  dart_flutter_team_lints: ^1.0.0
-  test: ^1.16.0
-  web_socket_channel: ^2.0.0
+  dart_flutter_team_lints: ^3.0.0
+  test: ^1.25.5
+  web_socket_channel: ^3.0.0
diff --git a/test/client/client_test.dart b/test/client/client_test.dart
index df9c033..1a4f65d 100644
--- a/test/client/client_test.dart
+++ b/test/client/client_test.dart
@@ -89,7 +89,7 @@
 
   test('sends a synchronous batch of requests', () {
     controller.expectRequest((request) {
-      expect(request, TypeMatcher<List>());
+      expect(request, isA<List>());
       expect(request, hasLength(3));
       expect(request[0], equals({'jsonrpc': '2.0', 'method': 'foo'}));
       expect(
@@ -121,7 +121,7 @@
 
   test('sends an asynchronous batch of requests', () {
     controller.expectRequest((request) {
-      expect(request, TypeMatcher<List>());
+      expect(request, isA<List>());
       expect(request, hasLength(3));
       expect(request[0], equals({'jsonrpc': '2.0', 'method': 'foo'}));
       expect(
@@ -143,14 +143,12 @@
     });
 
     controller.client.withBatch(() {
-      return Future.value().then((_) {
+      return Future<void>.value().then<void>((_) {
         controller.client.sendNotification('foo');
-        return Future.value();
-      }).then((_) {
+      }).then<void>((_) {
         expect(controller.client.sendRequest('bar', {'param': 'value'}),
             completion(equals('bar response')));
-        return Future.value();
-      }).then((_) {
+      }).then<void>((_) {
         expect(controller.client.sendRequest('baz'),
             completion(equals('baz response')));
       });
@@ -177,7 +175,7 @@
 
     expect(
         controller.client.sendRequest('foo', {'param': 'value'}),
-        throwsA(TypeMatcher<json_rpc.RpcException>()
+        throwsA(isA<json_rpc.RpcException>()
             .having((e) => e.code, 'code', error_code.SERVER_ERROR)
             .having((e) => e.message, 'message', 'you are bad at requests')
             .having((e) => e.data, 'data', 'some junk')));
diff --git a/test/client/utils.dart b/test/client/utils.dart
index acbfbe2..38e187f 100644
--- a/test/client/utils.dart
+++ b/test/client/utils.dart
@@ -32,7 +32,7 @@
   /// returns a String, that's sent as the response directly. If it returns
   /// null, no response is sent. Otherwise, the return value is encoded and sent
   /// as the response.
-  void expectRequest(Function(dynamic) callback) {
+  void expectRequest(FutureOr Function(dynamic) callback) {
     expect(
         _requestController.stream.first.then((request) {
           return callback(jsonDecode(request));
@@ -49,7 +49,7 @@
     sendJsonResponse(jsonEncode(response));
   }
 
-  /// Sends [response], a JSON-encoded response, to [client].
+  /// Sends [request], a JSON-encoded response, to [client].
   void sendJsonResponse(String request) {
     _responseController.add(request);
   }
diff --git a/test/peer_test.dart b/test/peer_test.dart
index 4b4c44a..0df6056 100644
--- a/test/peer_test.dart
+++ b/test/peer_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// ignore_for_file: inference_failure_on_instance_creation
+
 import 'dart:async';
 import 'dart:convert';
 
@@ -86,10 +88,10 @@
     });
 
     test('requests terminates when the channel is closed', () async {
-      var incomingController = StreamController();
+      var incomingController = StreamController<void>();
       var channel = StreamChannel.withGuarantees(
         incomingController.stream,
-        StreamController(),
+        StreamController<void>(),
       );
       var peer = json_rpc.Peer.withoutJson(channel);
       unawaited(peer.listen());
diff --git a/test/server/batch_test.dart b/test/server/batch_test.dart
index b8b8fea..af883c4 100644
--- a/test/server/batch_test.dart
+++ b/test/server/batch_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:json_rpc_2/error_code.dart' as error_code;
+import 'package:json_rpc_2/src/parameters.dart' show Parameters;
 import 'package:test/test.dart';
 
 import 'utils.dart';
@@ -14,8 +15,8 @@
     controller = ServerController();
     controller.server
       ..registerMethod('foo', () => 'foo')
-      ..registerMethod('id', (params) => params.value)
-      ..registerMethod('arg', (params) => params['arg'].value);
+      ..registerMethod('id', (Parameters params) => params.value)
+      ..registerMethod('arg', (Parameters params) => params['arg'].value);
   });
 
   test('handles a batch of requests', () {
diff --git a/test/server/server_test.dart b/test/server/server_test.dart
index 10f2678..b3166ce 100644
--- a/test/server/server_test.dart
+++ b/test/server/server_test.dart
@@ -16,7 +16,7 @@
   setUp(() => controller = ServerController());
 
   test('calls a registered method with the given name', () {
-    controller.server.registerMethod('foo', (params) {
+    controller.server.registerMethod('foo', (json_rpc.Parameters params) {
       return {'params': params.value};
     });
 
@@ -59,14 +59,19 @@
 
     expectErrorResponse(
         controller,
-        {'jsonrpc': '2.0', 'method': 'foo', 'params': {}, 'id': 1234},
+        {
+          'jsonrpc': '2.0',
+          'method': 'foo',
+          'params': <String, dynamic>{},
+          'id': 1234
+        },
         error_code.INVALID_PARAMS,
         'No parameters are allowed for method "foo".');
   });
 
   test('an unexpected error in a method is captured', () {
     controller.server
-        .registerMethod('foo', () => throw FormatException('bad format'));
+        .registerMethod('foo', () => throw const FormatException('bad format'));
 
     expect(
         controller
@@ -80,7 +85,7 @@
             'data': {
               'request': {'jsonrpc': '2.0', 'method': 'foo', 'id': 1234},
               'full': 'FormatException: bad format',
-              'stack': TypeMatcher<String>()
+              'stack': isA<String>()
             }
           }
         }));
@@ -90,8 +95,8 @@
     controller.server.registerMethod('foo', (args) => 'result');
 
     expect(
-        controller
-            .handleRequest({'jsonrpc': '2.0', 'method': 'foo', 'params': {}}),
+        controller.handleRequest(
+            {'jsonrpc': '2.0', 'method': 'foo', 'params': <String, dynamic>{}}),
         doesNotComplete);
   });
 
@@ -102,7 +107,12 @@
 
     expectErrorResponse(
         controller,
-        {'jsonrpc': '2.0', 'method': 'foo', 'params': {}, 'id': 1234},
+        {
+          'jsonrpc': '2.0',
+          'method': 'foo',
+          'params': <String, dynamic>{},
+          'id': 1234
+        },
         5,
         'Error message.',
         data: 'data value');
@@ -164,7 +174,7 @@
 
     test('an unexpected error in a fallback is captured', () {
       controller.server
-          .registerFallback((_) => throw FormatException('bad format'));
+          .registerFallback((_) => throw const FormatException('bad format'));
 
       expect(
           controller
@@ -178,7 +188,7 @@
               'data': {
                 'request': {'jsonrpc': '2.0', 'method': 'foo', 'id': 1234},
                 'full': 'FormatException: bad format',
-                'stack': TypeMatcher<String>()
+                'stack': isA<String>()
               }
             }
           }));
diff --git a/test/server/stream_test.dart b/test/server/stream_test.dart
index 2f95150..832e13c 100644
--- a/test/server/stream_test.dart
+++ b/test/server/stream_test.dart
@@ -23,7 +23,7 @@
   test('.withoutJson supports decoded stream and sink', () {
     server.listen();
 
-    server.registerMethod('foo', (params) {
+    server.registerMethod('foo', (json_rpc.Parameters params) {
       return {'params': params.value};
     });
 
diff --git a/test/server/utils.dart b/test/server/utils.dart
index 9fe6eed..c94628e 100644
--- a/test/server/utils.dart
+++ b/test/server/utils.dart
@@ -65,6 +65,6 @@
 /// Returns a matcher that matches a [json_rpc.RpcException] with an
 /// `invalid_params` error code.
 Matcher throwsInvalidParams(String message) =>
-    throwsA(TypeMatcher<json_rpc.RpcException>()
+    throwsA(isA<json_rpc.RpcException>()
         .having((e) => e.code, 'code', error_code.INVALID_PARAMS)
         .having((e) => e.message, 'message', message));