首先,我已经在Flutter的团队存储库上提交了一个问题,因为对我来说,这是一个关于Flutter/Dart的问题,但也许我错了。
复制步骤
flutter run上执行示例预期的结果:在“小部件示例”中创建一个具有类型属性的通用有状态小部件TypeErrorWidget<T>:
final IdMapper<T> idMapper;其中IdMapper<T>被定义为:
typedef IdMapper<T> = String Function(T item);稍后,将在状态内访问此属性,以映射可迭代的项并提取ids,并提供如下函数:
_itemsIds = widget.items.map((e) {
return widget.idMapper(e);
}).toList();我希望得到I作为List<String>的列表
实际结果:
但是,当运行时到达这一行时,它会失败地抱怨以下几点:'(ExampleListItem) => String' is not a subtype of type '(dynamic) => String',它没有多大意义,因为dynamic应该包含我的自定义类型。
代码样本
lib/presentation/widgets/type_error_widget.dart
class TypeErrorWidget<T> extends StatefulWidget {
final Iterable<T> items;
final IdMapper<T> idMapper;
const TypeErrorWidget({
Key? key,
required this.items,
required this.idMapper,
}) : super(key: key);
@override
State<TypeErrorWidget> createState() => _TypeErrorWidgetState();
}
class _TypeErrorWidgetState extends State<TypeErrorWidget> {
late List<String> _itemsIds;
@override
void initState() {
_itemsIds = widget.items.map((e) {
return widget.idMapper(e); <- it throws!
}).toList();
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text("I'll crash"),
Text(_itemsIds.toString()),
],
);
}
}
class WidgetExamplePage extends StatefulWidget {
const WidgetExamplePage({super.key});
@override
State<WidgetExamplePage> createState() => _WidgetExamplePageState();
}
class _WidgetExamplePageState extends State<WidgetExamplePage> {
bool _makeItCrash = false;
bool _makeItWork = false;
final List<ExampleListItem> _items = const [
ExampleListItem(
id: "id1",
title: "Title1",
),
ExampleListItem(
id: "id2",
title: "Title2",
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Widget error")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (_makeItCrash)
TypeErrorWidget<ExampleListItem>(
items: _items,
idMapper: (item) {
return item.id;
},
),
ElevatedButton(
onPressed: () {
setState(() {
_makeItWork = false;
_makeItCrash = true;
});
},
child: const Text("Make it crash"),
),
if (_makeItWork && !_makeItCrash)
TypeWorkaroundWidget<ExampleListItem>(
items: _items,
idMapper: (item) {
return item.id;
},
),
if (!_makeItCrash)
ElevatedButton(
onPressed: () {
setState(() {
_makeItWork = true;
_makeItCrash = false;
});
},
child: const Text("Make it works"),
),
],
),
),
);
}
} Logs The following _TypeError was thrown building KeyedSubtree-[GlobalKey#196d8]:
type '(ExampleListItem) => String' is not a subtype of type '(dynamic) => String'
The relevant error-causing widget was:
Scaffold
Scaffold:file:///Users/victor/Documents/personal/development/flutter/type_issues/lib/presentation/pages/widget_example_page.dart:29:12
When the exception was thrown, this was the stack:
#0 _TypeErrorWidgetState.initState.<anonymous closure> (package:type_issues/presentation/widgets/type_error_widget.dart:26:21)
#1 MappedListIterable.elementAt (dart:_internal/iterable.dart:413:31)
#2 ListIterator.moveNext (dart:_internal/iterable.dart:342:26)
#3 new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:189:27)
#4 new _GrowableList.of (dart:core-patch/growable_array.dart:150:28)
#5 new List.of (dart:core-patch/array_patch.dart:51:28)
#6 ListIterable.toList (dart:_internal/iterable.dart:213:44)
#7 _TypeErrorWidgetState.initState (package:type_issues/presentation/widgets/type_error_widget.dart:27:8)
#8 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5015:57)
#9 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4853:5)
#10 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3863:16)
#11 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6435:36)
#12 Element.updateChild (package:flutter/src/widgets/framework.dart:3592:18)
#13 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5964:32)
#14 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6460:17)
#15 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#16 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6307:14)
#17 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#18 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#19 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#20 StatelessElement.update (package:flutter/src/widgets/framework.dart:4956:5)
#21 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#22 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#23 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#24 StatelessElement.update (package:flutter/src/widgets/framework.dart:4956:5)
#25 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#26 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#27 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#28 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#29 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#30 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#31 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#32 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#33 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#34 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:5904:32)
#35 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6460:17)
#36 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#37 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#38 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#39 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#40 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#41 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#42 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#43 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#44 StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#45 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#46 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#47 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#48 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#49 StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#50 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#51 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#52 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#53 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#54 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#55 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#56 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#57 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#58 StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#59 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#60 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6307:14)
#61 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#62 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#63 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#64 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#65 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#66 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6307:14)
#67 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#68 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#69 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#70 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#71 StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#72 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#73 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#74 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#75 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#76 StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#77 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#78 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#79 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#80 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#81 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#82 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#83 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#84 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#85 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#86 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#87 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#88 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#89 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#90 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#91 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#92 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#93 StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#94 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#95 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#96 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#97 ProxyElement.update (package:flutter/src/widgets/framework.dart:5228:5)
#98 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#99 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#100 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#101 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#102 StatefulElement.update (package:flutter/src/widgets/framework.dart:5082:5)
#103 Element.updateChild (package:flutter/src/widgets/framework.dart:3570:15)
#104 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4904:16)
#105 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5050:11)
#106 Element.rebuild (package:flutter/src/widgets/framework.dart:4604:5)
#107 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2667:19)
#108 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:882:21)
#109 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:378:5)
#110 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1175:15)
#111 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1104:9)
#112 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1015:5)
#113 _invoke (dart:ui/hooks.dart:148:13)
#114 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#115 _drawFrame (dart:ui/hooks.dart:115:31)为了解决这个问题,我需要通过其构造函数将小部件属性向下传递到小部件状态:
lib/presentation/widgets/type_error_workaround.dart
...
@override
State<TypeWorkaroundWidget> createState() => _TypeErrorWidgetState<T>(
idMapper: idMapper,
);
...
class _TypeErrorWidgetState<T> extends State<TypeWorkaroundWidget> {
late List<String> _itemsIds;
final IdMapper<T> idMapper;
_TypeErrorWidgetState({
required this.idMapper,
});
@override
void initState() {
_itemsIds = widget.items.map((e) {
return idMapper(e) <-- it won't throw;
}).toList();
super.initState();
}除了我已经找到了解决办法的这个问题之外,我还有一个类似的问题,在本例中,我使用的是Freezed类型类:
lib/utils/types/freezed_example_type.dart
@freezed
class FreezedExampleType<T extends Object> with _$ExampleClass<T> {
factory FreezedExampleType.example({
required TypedFnExample<T> callback,
}) = _Example<T>;
}
typedef TypedFnExample<T> = String Function(T item);其思想是,稍后我可以将许多FreezedExampleType实例推到数组中,然后我可以根据类类型将一些逻辑放入其中,在我的示例中,我只通过按一个项简化了这一点:
class FreezedPage extends StatefulWidget {
const FreezedPage({super.key});
@override
State<FreezedPage> createState() => _FreezedPageState();
}
class _FreezedPageState extends State<FreezedPage> {
bool _makeItCrash = false;
bool _makeItWork = false;
List<FreezedExampleType> exampleType = List<FreezedExampleType>.of([]);
@override
void initState() {
exampleType.add(
FreezedExampleType<ExampleListItem>.example(
callback: (item) {
return item.id;
},
),
);
super.initState();
}
...稍后,我们访问数组上的类型并尝试对它的类型化属性采取行动:
_userType() {
const item = ExampleListItem(
id: "exampleId",
title: "Example Title",
);
print(
exampleType.first.mapOrNull(
example: (value) {
return value.callback(item); <- This will throw! =c
},
),
);
}不幸的是,这会引发相同类型的错误:type '(ExampleListItem) => String' is not a subtype of type '(Object) => String'
Logs ``` type '(ExampleListItem) => String' is not a subtype of type '(Object) => String' 当抛出异常时,这是堆栈:#0 _FreezedPageState._userType。(package:type_issues/presentation/pages/freezed_example_page.dart:86:24) #1 _$_Example.mapOrNull (package:type_issues/utils/types/freezed_example_type.freezed.dart:198:21) #2 _FreezedPageState._userType (package:type_issues/presentation/pages/freezed_example_page.dart:84:25) #3 _FreezedPageState.build.(package:type_issues/presentation/pages/freezed_example_page.dart:51:17) #4 _InkResponseState.handleTap #5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:253:24) #6 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:627:11) #7 BaseTapGestureRecognizer._checkUp (包装:颤振/src/手势/(package:flutter/src/gestures/recognizer.dart:615:9) #9 PrimaryPointerGestureRecognizer.handleEvent #10 PointerRouter._dispatch PointerRouter._dispatchEventToRoutes #11 PointerRouter._dispatchEventToRoutes。(package:flutter/src/gestures/pointer_router.dart:143:9) #12 _LinkedHashMapMixin.forEach #13 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:141:18) #14 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:127:7) #15 GestureBinding.handleEvent (包装:颤振/src/手势/binding.dart)::460:19) #16 (package:flutter/src/gestures/binding.dart:440:22) #17 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:337:11) #18 GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:395:7) #19 GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:357:5) #20 GestureBinding._flushPointerEventQueuesrc/ GestureBinding._handlePointerDataPacket /binding.dart:314:7) #21 GestureBinding._handlePointerDataPacket #22 _invoke1 (飞镖:ui/hooks.dart:167:13) #23 PlatformDispatcher._dispatchPointerDataPacket (飞镖:ui/platform_Dispatcher.dart:341:7) #24 _dispatchPointerDataPacket (飞镖:ui/hooks.dart:94:31)
处理器:"onTap“识别器: TapGestureRecognizer#90ba6
</details>
[1]: https://github.com/flutter/flutter/issues/110718发布于 2022-08-31 22:19:45
在TypeErrorWidget的state类中,将Type设置如下:
class TypeErrorWidget<T> extends StatefulWidget {
final Iterable<T> items;
final IdMapper<T> idMapper;
const TypeErrorWidget({
Key? key,
required this.items,
required this.idMapper,
}) : super(key: key);
@override
State<TypeErrorWidget<T>> createState() => _TypeErrorWidgetState<T>();
}
class _TypeErrorWidgetState<T> extends State<TypeErrorWidget<T>> {
late List<String> _itemsIds;
@override
void initState() {
_itemsIds = widget.items.map((e) {
return widget.idMapper(e);
}).toList();
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text("I'll crash"),
Text(_itemsIds.toString()),
],
);
}
}https://stackoverflow.com/questions/73562391
复制相似问题