类型“_CompactLinkedHashSet<String>”不是类型 'Map<dynamic, dynamic>?' 的子类型

type '_CompactLinkedHashSet<String>' is not a subtype of type 'Map<dynamic, dynamic>?'

我正在关注 tutorial 使用 flutter 和 rethinkdb 构建消息传递应用程序。它尚未针对空安全性进行更新,但作为初学者,我正在努力前进并使用最新的软件包和最新版本的 flutter 学习它。

我正在尝试测试输入通知,但遇到无法破译的错误。

type '_CompactLinkedHashSet<String>' is not a subtype of type 'Map<dynamic, dynamic>?'

package:rethink_db_ns/src/ast.dart:1223
TypingNotification.send
package:chat/…/typing/typing_notification.dart:22
main.<fn>
test/typing_notification_test.dart:44
main.<fn>
test/typing_notification_test.dart:37

我拥有的所有地图都是 Map,所以我不确定 Map 来自哪里。我用的也是package:rethink_db_ns,而不是教程作者用的,是添加ns之前的rethink包。所以我不确定我是否必须为新包做进一步的改变。在尝试 运行 测试之前,我还确保没有看到任何红色波浪线。

这是我的文件:

这是我尝试 运行 测试并得到上述错误的测试文件:

import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/models/user.dart';
import 'package:chat/src/services/typing/typing_notification.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:rethink_db_ns/rethink_db_ns.dart';

import 'helpers.dart';

void main() {
  RethinkDb r = RethinkDb();
  late Connection connection;
  late TypingNotification sut;

  setUp(() async {
    connection = await r.connect();
    await createDb(r, connection);
    sut = TypingNotification(r, connection);
  });

  tearDown(() async {
    sut.dispose();
    await cleanDb(r, connection);
  });

  final user = User.fromJson({
    'id': '1234',
    'active': true,
    'lastSeen': DateTime.now(),
  });

  final user2 = User.fromJson({
    'id': '1111',
    'active': true,
    'lastSeen': DateTime.now(),
  });

  test('sent typing notification successfully', () async {
    TypingEvent typingEvent = TypingEvent(
      from: user2.id!,
      to: user.id!,
      event: Typing.start,
    );

    final res = await sut.send(event: typingEvent, to: user);
    expect(res, true);
  });
}

这里是typing_notification.dart:

import 'dart:async';

import 'package:chat/src/models/user.dart';
import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/services/typing/typing_notification_service_contract.dart';
import 'package:rethink_db_ns/rethink_db_ns.dart';

class TypingNotification implements ITypingNotification {
  final Connection _connection;
  final RethinkDb _r;

  final _controller = StreamController<TypingEvent>.broadcast();
  StreamSubscription? _changefeed; // added ? to this

  TypingNotification(this._r, this._connection); //added this._change

  @override
  Future<bool> send({required TypingEvent event, required User to}) async {
    if (!to.active) return false;
    Map record = await _r
        .table('typing_events')
        .insert(event.toJson(), {'conflict:' 'update'}).run(_connection);
    return record['inserted'] == 1;
  }

  @override
  Stream<TypingEvent> subscribe(User user, List<String> userIds) {
    _startReceivingTypingEvents(user, userIds); 
    return _controller.stream;
  }

  @override
  void dispose() {
    _changefeed?.cancel();
    _controller.close();
  }

  _startReceivingTypingEvents(User user, List<String> userIds) {
    _changefeed = _r
        .table('typing_events')
        .filter((event) {
          return event('to')
              .eq(user.id)
              .and(_r.expr(userIds).contains(event('from')));
        })
        .changes({'include_initial': true})
        .run(_connection)
        .asStream()
        .cast<Feed>()
        .listen((event) {
          event
              .forEach((feedData) {
                if (feedData['new_val'] == null) return;

                final typing = _eventFromFeed(feedData);
                _controller.sink.add(typing);
                _removeEvent(typing);
              })
              .catchError((err) => print(err))
              .onError((error, stackTrace) => print(error));
        });
  }

  TypingEvent _eventFromFeed(feedData) {
    return TypingEvent.fromJson(feedData['new_val']);
  }

  _removeEvent(TypingEvent event) {
    _r
        .table('typing_events')
        .get(event.id)
        .delete({'return_changes': false}).run(_connection);
  }
}

这里是typing_event.dart:

enum Typing { start, stop }

extension TypingParser on Typing {
  String value() {
    return toString().split('.').last;
  }

  static Typing fromString(String event) {
    return Typing.values.firstWhere((element) => element.value() == event);
  }
}

class TypingEvent {
  final String from;
  final String to;
  final Typing event;
  String? _id;
  String? get id => _id;

  TypingEvent({
    required this.from,
    required this.to,
    required this.event,
  });

  Map<String, dynamic> toJson() => { 
        'from': this.from,
        'to': this.to,
        'event': this.event.value(),
      };

  factory TypingEvent.fromJson(Map<String, dynamic> json) { 
    var event = TypingEvent(
      from: json['from'],
      to: json['to'],
      event: TypingParser.fromString(json['event']),
    );
    event._id = json['id'];
    return event;
  }
}

这里是 typing_notification_service_contract.dart:

import 'package:chat/src/models/typing_event.dart';
import 'package:chat/src/models/user.dart';

abstract class ITypingNotification {
  Future<bool> send(
      {required TypingEvent event, required User to}); // the tutorial did not include ", required User to" but I added it to prevent an error, since required User to is passed in another file 
  Stream<TypingEvent> subscribe(User user, List<String> userIds);
  void dispose();
}

最后,typing_event.dart

enum Typing { start, stop }

extension TypingParser on Typing {
  String value() {
    return toString().split('.').last;
  }

  static Typing fromString(String event) {
    return Typing.values.firstWhere((element) => element.value() == event);
  }
}

class TypingEvent {
  final String from;
  final String to;
  final Typing event;
  String? _id;
  String? get id => _id;

  TypingEvent({
    required this.from,
    required this.to,
    required this.event,
  });

  Map<String, dynamic> toJson() => { 
        'from': this.from,
        'to': this.to,
        'event': this.event.value(),
      };

  factory TypingEvent.fromJson(Map<String, dynamic> json) { 
    var event = TypingEvent(
      from: json['from'],
      to: json['to'],
      event: TypingParser.fromString(json['event']),
    );
    event._id = json['id'];
    return event;
  }
}

我是一个完全的初学者,并试图推动自己学习空安全,所以我的错误很可能很简单,我只是没有看到它。任何人都可以指出我正确的方向或在这里提供任何指导吗?如果您认为可能有帮助,我还可以根据要求添加更多详细信息。

尝试更换

.insert(event.toJson(), {'conflict:' 'update'}).run(_connection);

 .insert(event.toJson(), {'conflict': 'update'}).run(_connection);

在第 22 行 typing_notification,.dart 中,它期待 Map,可能您打算将“:”放在字符串之外