Require Dart 3.3, update and fix lints (#100)

diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml
index 41ca690..db6451b 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.3, dev]
     steps:
       - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
       - uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c78f64f..4b8e2b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.1.3-wip
+
+* Require Dart 3.3
+
 ## 2.1.2
 
 * Require Dart 2.19
diff --git a/example/example.dart b/example/example.dart
index dd16f67..b41d8d9 100644
--- a/example/example.dart
+++ b/example/example.dart
@@ -22,7 +22,7 @@
   // For example, we can handle standard input as strings:
   var stringChannel = stdioChannel
       .transform(StreamChannelTransformer.fromCodec(utf8))
-      .transformStream(LineSplitter());
+      .transformStream(const LineSplitter());
   stringChannel.sink.add('world!\n');
 
   // You can implement StreamChannel<T> by extending StreamChannelMixin<T>, but
@@ -84,8 +84,8 @@
   // given the corresponding `SendPort`, and then call
   // `IsolateChannel.connectSend`.
   var recv = ReceivePort();
-  var recvChannel = IsolateChannel.connectReceive(recv);
-  var sendChannel = IsolateChannel.connectSend(recv.sendPort);
+  var recvChannel = IsolateChannel<void>.connectReceive(recv);
+  var sendChannel = IsolateChannel<void>.connectSend(recv.sendPort);
 
   // You must manually close `IsolateChannel<T>` sinks, however.
   await recvChannel.sink.close();
diff --git a/lib/src/disconnector.dart b/lib/src/disconnector.dart
index 61969cb..3414e9c 100644
--- a/lib/src/disconnector.dart
+++ b/lib/src/disconnector.dart
@@ -38,7 +38,7 @@
         _sinks.clear();
         return Future.wait(futures, eagerError: true);
       });
-  final _disconnectMemo = AsyncMemoizer();
+  final _disconnectMemo = AsyncMemoizer<List<void>>();
 
   @override
   StreamChannel<T> bind(StreamChannel<T> channel) {
diff --git a/lib/src/guarantee_channel.dart b/lib/src/guarantee_channel.dart
index 2aa8b7b..30ebe2e 100644
--- a/lib/src/guarantee_channel.dart
+++ b/lib/src/guarantee_channel.dart
@@ -83,7 +83,7 @@
 
   @override
   Future<void> get done => _doneCompleter.future;
-  final _doneCompleter = Completer();
+  final _doneCompleter = Completer<void>();
 
   /// Whether connection is disconnected.
   ///
diff --git a/lib/src/isolate_channel.dart b/lib/src/isolate_channel.dart
index 3fbd46d..15c68a4 100644
--- a/lib/src/isolate_channel.dart
+++ b/lib/src/isolate_channel.dart
@@ -51,7 +51,7 @@
         .transform(StreamSinkTransformer.fromHandlers(handleDone: (sink) {
       if (!isCompleted) {
         receivePort.close();
-        streamCompleter.setSourceStream(Stream.empty());
+        streamCompleter.setSourceStream(const Stream.empty());
         sinkCompleter.setDestinationSink(NullStreamSink<T>());
       }
       sink.close();
diff --git a/lib/src/multi_channel.dart b/lib/src/multi_channel.dart
index 82f59c7..4894239 100644
--- a/lib/src/multi_channel.dart
+++ b/lib/src/multi_channel.dart
@@ -191,7 +191,8 @@
     // If the inner channel has already closed, create new virtual channels in a
     // closed state.
     if (_inner == null) {
-      return VirtualChannel._(this, inputId, Stream.empty(), NullStreamSink());
+      return VirtualChannel._(
+          this, inputId, const Stream.empty(), NullStreamSink());
     }
 
     late StreamChannelController<T> controller;
diff --git a/lib/src/stream_channel_completer.dart b/lib/src/stream_channel_completer.dart
index 5a824c1..9d007eb 100644
--- a/lib/src/stream_channel_completer.dart
+++ b/lib/src/stream_channel_completer.dart
@@ -34,7 +34,7 @@
   /// instead contain just that error. The sink will silently discard all
   /// events.
   static StreamChannel fromFuture(Future<StreamChannel> channelFuture) {
-    var completer = StreamChannelCompleter();
+    var completer = StreamChannelCompleter<void>();
     channelFuture.then(completer.setChannel, onError: completer.setError);
     return completer.channel;
   }
diff --git a/pubspec.yaml b/pubspec.yaml
index 0b4f62d..0cfd074 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,16 +1,16 @@
 name: stream_channel
-version: 2.1.2
+version: 2.1.3-wip
 description: >-
   An abstraction for two-way communication channels based on the Dart Stream
   class.
 repository: https://github.com/dart-lang/stream_channel
 
 environment:
-  sdk: '>=2.19.0 <3.0.0'
+  sdk: ^3.3.0
 
 dependencies:
   async: ^2.5.0
 
 dev_dependencies:
-  dart_flutter_team_lints: ^1.0.0
+  dart_flutter_team_lints: ^2.0.0
   test: ^1.16.0
diff --git a/test/disconnector_test.dart b/test/disconnector_test.dart
index 28f3fee..bbba568 100644
--- a/test/disconnector_test.dart
+++ b/test/disconnector_test.dart
@@ -14,8 +14,8 @@
   late Disconnector disconnector;
   late StreamChannel channel;
   setUp(() {
-    streamController = StreamController();
-    sinkController = StreamController();
+    streamController = StreamController<void>();
+    sinkController = StreamController<void>();
     disconnector = Disconnector();
     channel = StreamChannel.withGuarantees(
             streamController.stream, sinkController.sink)
@@ -52,7 +52,7 @@
     });
 
     test("events can't be added while a stream is being added", () {
-      var controller = StreamController();
+      var controller = StreamController<void>();
       channel.sink.addStream(controller.stream);
 
       expect(() => channel.sink.add(1), throwsStateError);
@@ -67,7 +67,7 @@
 
   test('cancels addStream when disconnected', () async {
     var canceled = false;
-    var controller = StreamController(onCancel: () {
+    var controller = StreamController<void>(onCancel: () {
       canceled = true;
     });
     expect(channel.sink.addStream(controller.stream), completes);
@@ -78,9 +78,9 @@
   });
 
   test('disconnect() returns the close future from the inner sink', () async {
-    var streamController = StreamController();
-    var sinkController = StreamController();
-    var disconnector = Disconnector();
+    var streamController = StreamController<void>();
+    var sinkController = StreamController<void>();
+    var disconnector = Disconnector<void>();
     var sink = _CloseCompleterSink(sinkController.sink);
     StreamChannel.withGuarantees(streamController.stream, sink)
         .transform(disconnector);
@@ -140,7 +140,7 @@
 /// returned by [close] using [completer].
 class _CloseCompleterSink extends DelegatingStreamSink {
   /// The completer for the future returned by [close].
-  final completer = Completer();
+  final completer = Completer<void>();
 
   _CloseCompleterSink(super.inner);
 
diff --git a/test/isolate_channel_test.dart b/test/isolate_channel_test.dart
index 10f1fe5..3a8b42e 100644
--- a/test/isolate_channel_test.dart
+++ b/test/isolate_channel_test.dart
@@ -53,7 +53,7 @@
   });
 
   test("events can't be added while a stream is being added", () {
-    var controller = StreamController();
+    var controller = StreamController<void>();
     channel.sink.addStream(controller.stream);
 
     expect(() => channel.sink.add(1), throwsStateError);
@@ -109,7 +109,7 @@
     test('the sink closes as soon as an error is added via addStream',
         () async {
       var canceled = false;
-      var controller = StreamController(onCancel: () {
+      var controller = StreamController<void>(onCancel: () {
         canceled = true;
       });
 
@@ -156,7 +156,7 @@
 
     test('the receiving channel produces an error if it gets the wrong message',
         () {
-      var connectedChannel = IsolateChannel.connectReceive(connectPort);
+      var connectedChannel = IsolateChannel<int>.connectReceive(connectPort);
       connectPort.sendPort.send('wrong value');
 
       expect(connectedChannel.stream.toList(), throwsStateError);
@@ -165,7 +165,7 @@
 
     test('the receiving channel closes gracefully without a connection',
         () async {
-      var connectedChannel = IsolateChannel.connectReceive(connectPort);
+      var connectedChannel = IsolateChannel<int>.connectReceive(connectPort);
       await connectedChannel.sink.close();
       await expectLater(connectedChannel.stream.toList(), completion(isEmpty));
       await expectLater(connectedChannel.sink.done, completes);
diff --git a/test/json_document_transformer_test.dart b/test/json_document_transformer_test.dart
index 48d8f72..290c4e2 100644
--- a/test/json_document_transformer_test.dart
+++ b/test/json_document_transformer_test.dart
@@ -41,6 +41,6 @@
   test('synchronously throws if an unencodable object is added', () {
     var transformed = channel.transform(jsonDocument);
     expect(() => transformed.sink.add(Object()),
-        throwsA(TypeMatcher<JsonUnsupportedObjectError>()));
+        throwsA(const TypeMatcher<JsonUnsupportedObjectError>()));
   });
 }
diff --git a/test/stream_channel_completer_test.dart b/test/stream_channel_completer_test.dart
index 22db01a..c6fddc0 100644
--- a/test/stream_channel_completer_test.dart
+++ b/test/stream_channel_completer_test.dart
@@ -14,8 +14,8 @@
   late StreamChannel innerChannel;
   setUp(() {
     completer = StreamChannelCompleter();
-    streamController = StreamController();
-    sinkController = StreamController();
+    streamController = StreamController<void>();
+    sinkController = StreamController<void>();
     innerChannel = StreamChannel(streamController.stream, sinkController.sink);
   });
 
diff --git a/test/stream_channel_test.dart b/test/stream_channel_test.dart
index 76edbdf..c44b6ab 100644
--- a/test/stream_channel_test.dart
+++ b/test/stream_channel_test.dart
@@ -10,21 +10,17 @@
 import 'package:test/test.dart';
 
 void main() {
-  late StreamController streamController;
-  late StreamController sinkController;
-  late StreamChannel channel;
-  setUp(() {
-    streamController = StreamController();
-    sinkController = StreamController();
-    channel = StreamChannel(streamController.stream, sinkController.sink);
-  });
-
   test("pipe() pipes data from each channel's stream into the other's sink",
       () {
-    var otherStreamController = StreamController();
-    var otherSinkController = StreamController();
+    var otherStreamController = StreamController<int>();
+    var otherSinkController = StreamController<int>();
     var otherChannel =
         StreamChannel(otherStreamController.stream, otherSinkController.sink);
+
+    var streamController = StreamController<int>();
+    var sinkController = StreamController<int>();
+    var channel = StreamChannel(streamController.stream, sinkController.sink);
+
     channel.pipe(otherChannel);
 
     streamController.add(1);
@@ -41,6 +37,10 @@
   });
 
   test('transform() transforms the channel', () async {
+    var streamController = StreamController<List<int>>();
+    var sinkController = StreamController<List<int>>();
+    var channel = StreamChannel(streamController.stream, sinkController.sink);
+
     var transformed = channel
         .cast<List<int>>()
         .transform(StreamChannelTransformer.fromCodec(utf8));
@@ -59,6 +59,10 @@
   });
 
   test('transformStream() transforms only the stream', () async {
+    var streamController = StreamController<String>();
+    var sinkController = StreamController<String>();
+    var channel = StreamChannel(streamController.stream, sinkController.sink);
+
     var transformed =
         channel.cast<String>().transformStream(const LineSplitter());
 
@@ -75,8 +79,12 @@
   });
 
   test('transformSink() transforms only the sink', () async {
+    var streamController = StreamController<String>();
+    var sinkController = StreamController<String>();
+    var channel = StreamChannel(streamController.stream, sinkController.sink);
+
     var transformed = channel.cast<String>().transformSink(
-        StreamSinkTransformer.fromStreamTransformer(const LineSplitter()));
+        const StreamSinkTransformer.fromStreamTransformer(LineSplitter()));
 
     streamController.add('fbl\nthp');
     unawaited(streamController.close());
@@ -91,7 +99,11 @@
   });
 
   test('changeStream() changes the stream', () {
-    var newController = StreamController();
+    var streamController = StreamController<int>();
+    var sinkController = StreamController<int>();
+    var channel = StreamChannel(streamController.stream, sinkController.sink);
+
+    var newController = StreamController<int>();
     var changed = channel.changeStream((stream) {
       expect(stream, equals(channel.stream));
       return newController.stream;
@@ -107,7 +119,11 @@
   });
 
   test('changeSink() changes the sink', () {
-    var newController = StreamController();
+    var streamController = StreamController<int>();
+    var sinkController = StreamController<int>();
+    var channel = StreamChannel(streamController.stream, sinkController.sink);
+
+    var newController = StreamController<int>();
     var changed = channel.changeSink((sink) {
       expect(sink, equals(channel.sink));
       return newController.sink;
diff --git a/test/with_close_guarantee_test.dart b/test/with_close_guarantee_test.dart
index a18f09f..9c0b729 100644
--- a/test/with_close_guarantee_test.dart
+++ b/test/with_close_guarantee_test.dart
@@ -45,7 +45,7 @@
             .listen(expectAsync1((event) {
               if (event == 2) channel.sink.close();
             }, count: 2))
-            .asFuture(),
+            .asFuture<void>(),
         completes);
 
     await pumpEventQueue();
diff --git a/test/with_guarantees_test.dart b/test/with_guarantees_test.dart
index 849e304..f026079 100644
--- a/test/with_guarantees_test.dart
+++ b/test/with_guarantees_test.dart
@@ -12,8 +12,8 @@
   late StreamController sinkController;
   late StreamChannel channel;
   setUp(() {
-    streamController = StreamController();
-    sinkController = StreamController();
+    streamController = StreamController<void>();
+    sinkController = StreamController<void>();
     channel = StreamChannel.withGuarantees(
         streamController.stream, sinkController.sink);
   });
@@ -53,7 +53,7 @@
             .listen(expectAsync1((event) {
               if (event == 2) channel.sink.close();
             }, count: 2))
-            .asFuture(),
+            .asFuture<void>(),
         completes);
   });
 
@@ -126,7 +126,7 @@
   });
 
   test("events can't be added while a stream is being added", () {
-    var controller = StreamController();
+    var controller = StreamController<void>();
     channel.sink.addStream(controller.stream);
 
     expect(() => channel.sink.add(1), throwsStateError);
@@ -140,8 +140,8 @@
 
   group('with allowSinkErrors: false', () {
     setUp(() {
-      streamController = StreamController();
-      sinkController = StreamController();
+      streamController = StreamController<void>();
+      sinkController = StreamController<void>();
       channel = StreamChannel.withGuarantees(
           streamController.stream, sinkController.sink,
           allowSinkErrors: false);
@@ -166,7 +166,7 @@
               .listen(expectAsync1((event) {
                 if (event == 2) channel.sink.addError('oh no');
               }, count: 2))
-              .asFuture(),
+              .asFuture<void>(),
           completes);
     });
 
@@ -180,7 +180,7 @@
         'adding an error via via addStream causes the stream to emit a done '
         'event', () async {
       var canceled = false;
-      var controller = StreamController(onCancel: () {
+      var controller = StreamController<void>(onCancel: () {
         canceled = true;
       });