freezedのモデルに共通利用するメソッドを拡張する

9257 ワード

下記のようなcreatedAt, updatedAtがあるfreezedのモデルに対して、formattedCreatedAtString, formattedUpdatedAtString の実装を共通化する場合、下記のように BaseModel クラスを定義/implementsして、 BaseModelextension で実装すると動く。

import 'package:freezed_annotation/freezed_annotation.dart';

part 'freezed_model.freezed.dart';


class FreezedModel with _$FreezedModel implements BaseModel {
  const FreezedModel._();
 
  factory FreezedModel({
    required String id,
    required DateTime createdAt,
    required DateTime updatedAt,
  }) = _FreezedModel;
}

abstract class BaseModel {
  const BaseModel();
  
  DateTime get createdAt;
  DateTime get updatedAt;
}

extension BaseModelEx on BaseModel {
  String get formattedCreatedAtString => createdAt.formattedString(format: 'yyyy/MM/dd(E)');
  String get formattedUpdatedAtString => updatedAt.formattedString(format: 'yyyy/MM/dd(E)');
}

extension DateTimeEx on DateTime {
  String formattedString({String format = 'yyyy/MM/dd(E) HH:mm'}) {
    final formatter = DateFormat(format, 'ja_JP');
    final formattedString = formatter.format(this);
    return formattedString;
  }
}

ビルドエラーになるパターン

下記のようmixinにすると、freezedのモデルだとビルドエラーになる。

import 'package:freezed_annotation/freezed_annotation.dart';

part 'freezed_model.freezed.dart';


class FreezedModel with _$FreezedModel, BaseModelMixin {
  factory FreezedModel({
    required String id,
    required DateTime createdAt,
    required DateTime updatedAt,
  }) = _FreezedModel;
}

mixin BaseModelMixin {
  void printName(String name) {
    print(name);
  }
}

ビルドエラー

    Error: The non-abstract class '_$_FreezedModel' is missing implementations for these members:
     - BaseModelMixin.printName
    Try to either
     - provide an implementation,
     - inherit an implementation from a superclass or mixin,
     - mark the class as abstract, or
     - provide a 'noSuchMethod' implementation.