You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The generated draft class implements User, which adds an implicit conformance requirement to Equatable.
Given how the generator currently works, the generated output won’t compile due to a missing member required by Equatable.
// ❌ Missing concrete implementation of 'getter abstract class Equatable.stringify'. Try implementing the missing method, or make the class abstract.classUserDraftimplementsUser {
// Mutable fieldsint name;
// Getters and setters for nested draftable fieldsUserDraft({requiredthis.name});
Usersave() =>User(name: name);
@overrideList<Object?> get props =>save().props;
}
Given how ubiquitous packages like equatable are, it would be convenient if draft allowed marking classes that declare explicit supertypes as draftable.
Some obvious solutions that come to mind are:
Forward getters and methods from supertypes in a similar fashion to forwarding members of the annotated type.
Don't implementing the annotated type in the generated draft class.
The motivation here is that the responsibility of the draft type is to provide a way to update fields of its immutable counterpart and implementing the annotated type may go beyond that responsibility while increasing the complexity of the generated code.
There might be some additional context I’m not aware of, such as how immerjs works or draft’s prior design decisions, so I’m not entirely sure what the preferable approach would be.
@tomwyr Another option I've used here is the EquatableMixin mixin. It will extend the class without requiring a concrete implementation. Does this work for you?
Ah, gotcha. I suppose if we wanted to support that, we could make the generated draft class implement the super interfaces also, and then call the main class's methods by saving first then invoking them. From your example:
classDataDraftimplementsData {
@overrideList<Object?> get props =>save().props; // convert back to Data, then ret props
}
I believe that would be sufficient to support extending base classes.
As far as I can see, in the generator we could leverage classElement.allSupertypes or classElement.inheritedConcreteMembers/classElement.inheritedMembers to access members of the base type(s) included in the generated code too. There might be some additional work required to deduplicate fields (what if the draftable class overrides a getter or a method).
Activity
josiahsrc commentedon Dec 30, 2025
@tomwyr Another option I've used here is the
EquatableMixinmixin. It will extend the class without requiring a concrete implementation. Does this work for you?tomwyr commentedon Dec 30, 2025
Changing the declaration to use the mixin instead does help, thanks.
Originally, I encountered this issue while trying to annotate a subclass of a sealed type as draftable, roughly as follows:
josiahsrc commentedon Dec 30, 2025
Ah, gotcha. I suppose if we wanted to support that, we could make the generated draft class implement the super interfaces also, and then call the main class's methods by saving first then invoking them. From your example:
tomwyr commentedon Dec 30, 2025
I believe that would be sufficient to support extending base classes.
As far as I can see, in the generator we could leverage
classElement.allSupertypesorclassElement.inheritedConcreteMembers/classElement.inheritedMembersto access members of the base type(s) included in the generated code too. There might be some additional work required to deduplicate fields (what if the draftable class overrides a getter or a method).josiahsrc commentedon Dec 31, 2025
Sounds like a plan
tomwyr commentedon Jan 1, 2026
I might give it a try in the coming days and draft a PR to validate the idea, verify there will be no caveats, etc.
josiahsrc commentedon Jan 1, 2026
Sweet, I'll keep an eye out. Happy new year @tomwyr !