-
-
Notifications
You must be signed in to change notification settings - Fork 301
Closed
Labels
Description
Hi! I'm hitting a compilation error caused by generated code typing a List<ConcreteType> field as List<dynamic> inside $CopyWith.
This is happening in a @Freezed(unionKey: ...) sealed union that implements a generic interface Task<T extends BaseItem> and mixes in logic TaskLogic<T>. The field is explicitly declared as List<StepItem> in both union cases.
Expected
Generated $CopyWith should keep the concrete type:
List<StepItem> items(notList<dynamic>)- no null-assertion
items!since the field is required/non-nullable
Actual
Generated code contains:
$TaskModelCopyWith.call(... items: List<dynamic> ...)- casts like
as List<dynamic> - uses
items!even though the field is non-nullable/required
This leads to compilation error in the generated file.
Reproduction
1) Models / Interfaces / mixins
// base_item.dart
import 'package:freezed_annotation/freezed_annotation.dart';
part 'base_item.freezed.dart';
part 'base_item.g.dart';
@freezed
sealed class BaseItem with _$BaseItem {
const BaseItem._();
const factory BaseItem({
required int order,
)} = _BaseItem;
const factory BaseItem.stepItem({
required int order,
}) = StepItem;
factory BaseItem.fromJson(Map<String, dynamic> json) => _$BaseItemFromJson(json);
}// task_interfaces.dart
abstract class Task<T extends BaseItem> {
List<T> get items;
}
mixin TaskLogic<T extends BaseItem> {
List<T> get items;
List<T> get orderedItems => List.of(items)..sort((a, b) => a.order - b.order);
int get itemsCount => items.length;
}2) The working union
// task_a_model.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'task_interfaces.dart';
import 'item.dart';
part 'task_a_model.freezed.dart';
part 'task_a_model.g.dart';
@Freezed(unionKey: 'type')
sealed class TaskAModel with _$TaskAModel {
const TaskAModel._();
@FreezedUnionValue('a')
@Implements<Task>()
@With<TaskLogic>()
const factory TaskAModel.a({
required List<BaseItem> items,
}) = _A;
@FreezedUnionValue('b')
const factory TaskAModel.b({
required String name,
}) = _B;
}
3) The failing union
// task_b_model.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'task_interfaces.dart';
import 'item.dart';
part 'task_b_model.freezed.dart';
part 'task_b_model.g.dart';
@Freezed(unionKey: 'type')
sealed class TaskBModel
with _$TaskBModel, TaskLogic<StepItem>
implements Task<StepItem> {
const TaskBModel._();
@FreezedUnionValue('a')
const factory TaskBModel.a({
required List<StepItem> items,
}) = _A;
@FreezedUnionValue('b')
const factory TaskBModel.b({
required List<StepItem> items,
required String extra,
}) = _B;
factory TaskBModel.fromJson(Map<String, dynamic> json) => _$TaskBModelFromJson(json);
}4) Generated output (problematic excerpt)
In the generated file, $TaskBModelCopyWith uses List<dynamic> instead of List<StepItem>, and may emit items!.
Example (illustrative):
abstract mixin class $TaskBModelCopyWith<$Res> {
$Res call({ List<dynamic> items, ... });
}Environment
- Dart: 3.11.0
- Flutter: 3.41.1
- freezed: 3.2.5
- freezed_annotation: 3.1.0
- build_runner: 2.11.1
- json_serializable: 6.12.0
Reactions are currently unavailable