概要
どうも、@daiki1003です!前著JsonKey
チートシートがそこそこ好評だったでした。
そのため、freezed
も需要あるのではと思い、書いてみました!
・freezed
使ってるけど、使いこなせてる感じはしない
・freezed
のoptionって何があるかわかっていない
と言う方に向けてわかりやすく解説したいと思うのでぜひご覧いただければと思います。
執筆時環境
名前 | バージョン |
Flutter | 3.7.12 |
freezed | 2.3.2 |
unionKey
Union
をシリアライズ/デシリアライズする際に使用するキーを指定します。
デフォルトは、runtimeType
です。
class Union with _$Union { factory Union.first() = _First; factory Union.second() = _Second; factory Union.fromJson(Map<String, Object> json) => _$UnionFromJson(json); }
とした定義があるとします。
この時、json
をパースしようとすると
{'runtimeType': 'first'} // Union.first {'runtimeType': 'second'} // Union.second
となるのですが、
@Freezed(unionKey: 'type') class Union with _$Union { // ... }
とすることで、
{'type': 'first'} // Union.first {'type': 'second'} // Union.second
となります。
toJson
の出力も同様に変化します。
unionValueCase
Union
をシリアライズ/デシリアライズする際に、バリューの命名規則について指定します。
先ほどの実装を
@Freezed(unionValueCase: FreezedUnionCase.snake) class Union with _$Union { // ... }
とすることで、
{'runtime_type': 'first'} // Union.first {'runtime_type': 'second'} // Union.second
となります。
fallbackUnion
Union
が正しくデシリアライズできなかった場合に、代わりに使用するUnion
を指定します。
@Freezed(fallbackUnion: 'first') class Union with _$Union { // ... }
とすることで、
{'runtimeType': 'first'} // Union.first {'runtimeType': 'second'} // Union.second {'runtimeType': 'third'} // Union.first
となります。
copyWith
copyWith
を生成するかどうかを指定します。
デフォルトは、true
です。
もし、null
なら、build.yaml
の値を見に行きます。
それもnull
なら、デフォルト値のtrue
が採用されます。
equal
==/hashcode
を生成するかどうかを指定します。
デフォルトは、null
です。
もし、null
なら、build.yaml
の値を見に行きます。
それもnull
なら、独自に==
が実装されていない場合のみ==/hashcode
が生成されます。
toStringOverride
toString
を生成するかどうかを指定します。
デフォルトは、null
です。
もし、null
なら、build.yaml
の値を見に行きます。
それもnull
なら、独自にtoString
が実装されていない場合のみtoString
が生成されます。
fromJson
fromJson
を生成するかどうかを指定します。
デフォルトは、null
です。
もし、null
なら、build.yaml
の値を見に行きます。
それもnull
なら、対象のクラスがfromJson
を
@freezed class Example with _$Example { factory Example(int a) = _Example; factory Example.fromJson(Map<String, Object?> json) => _$ExampleFromJson(json); }
の様に、実装している場合のみ生成します。
逆に、以下の様に実装している場合は、生成されません。
@freezed class Example with _$Example { factory Example(int a) = _Example; factory Example.fromJson(Map<String, Object?> json) { // `=>` ではなく `{ return }` を使っているため生成されない return {...}; } }
—
と、書いてはいるのですが、実際に何をreturn
すればいいのか、現状わかっていません。
詳しい人教えてください🙏
toJson
toJson
を生成するかどうかを指定します。
デフォルトは、null
です。
もし、null
なら、build.yaml
の値を見に行きます。
それもnull
なら、対象のクラスがfromJson
を
@freezed class Example with _$Example { factory Example(int a) = _Example; factory Example.fromJson(Mapjson) => _$ExampleFromJson(json); }
の様に、実装している場合のみ生成します。
逆に、以下の様に実装している場合は、生成されません。
@freezed class Example with _$Example { factory Example(int a) = _Example; factory Example.fromJson(Map<String, Object?> json) { // `=>` ではなく `{ return }` を使っているため生成されない return {...}; } }
—
と、ここまで全くfromJson
と同じ説明を書いていますが間違いではありません。fromJson/toJson
はペアの存在ですので、fromJson
の有無はtoJson
の有無に一致する様になっているのです。
map
map
、mapOrNull
, maybeMap
メソッドを
それぞれ生成するかを指定できます。
FreezedMapOption
はコメントアウト部分を除くと以下のような定義になっています。
class FreezedMapOptions { const FreezedMapOptions({ this.map, this.mapOrNull, this.maybeMap, }); factory FreezedMapOptions.fromJson(Map json) => _$FreezedMapOptionsFromJson(json); static const all = FreezedMapOptions( map: true, mapOrNull: true, maybeMap: true, ); static const none = FreezedMapOptions( map: false, mapOrNull: false, maybeMap: false, ); final bool? map; final bool? mapOrNull; final bool? maybeMap; }
それぞれ生成するかどうかを指定できます。
デフォルトはnull
です。
もし、null
なら、build.yaml
の値を見に行きます。
それもnull
なら、FreezedMapOptions.all
、つまり全部生成する様になります。
—
個人的には、mapOrNull
やmaybeMap
はunion
の良さを一つ消してしまうので、map
のみの生成が良いと思っています。
理由としては、 orElse
などの「その他」と言う指定の仕方をしてしまうと新しい要素を追加した時にorElse
に吸い込まれてしまい、コンパイルも通ってしまうため使用箇所の確認を怠ってしまう可能性があるからです。
この際、build.yaml
には以下の様に記述します。
targets: $default: builders: freezed: options: map: map_or_null: false maybe_map: false
when
when
、whenOrNull
, maybeWhen
メソッドを
それぞれ生成するかを指定できます。
FreezedWhenOption
はコメントアウト部分を除くと以下のような定義になっています。
class FreezedWhenOptions { const FreezedWhenOptions({ this.when, this.whenOrNull, this.maybeWhen, }); factory FreezedWhenOptions.fromJson(Map json) => _$FreezedWhenOptionsFromJson(json); static const all = FreezedWhenOptions( when: true, whenOrNull: true, maybeWhen: true, ); static const none = FreezedWhenOptions( when: false, whenOrNull: false, maybeWhen: false, ); final bool? when; final bool? whenOrNull; final bool? maybeWhen; }
それぞれ生成するかどうかを指定できます。
デフォルトはnull
です。
もし、null
なら、build.yaml
の値を見に行きます。
それもnull
なら、FreezedWhenOptions.all
、つまり全部生成する様になります。
—
個人的には、whenOrNull
やmaybeWhen
はunion
の良さを一つ消してしまうので、when
のみの生成が良いと思っています。
理由は、map
の方を参照してください。
この際、build.yaml
には以下の様に記述します。
targets: $default: builders: freezed: options: when: when_or_null: false maybe_when: false
makeCollectionsUnmodifiable
List
, Map
, Set
をそれぞれUnmodifiableListView
, UnmodifiableMapView
,UnmodifiableSetView
に変換するかを指定できます。
デフォルトはtrue
です。
—
なんで接尾辞View
なんだろう…。
addImplicitFinal
明示的にコンストラクタの引数パラメタにfinalを付与するかを指定できます。
デフォルトはtrue
です。
@Freezed(addImplicitFinal: true) // なくても良い class Person with _$Person { factory Person(String name, int age) = _Person; }
は、以下と同義になります。
@Freezed(addImplicitFinal: false) class Person with _$Person { factory Person(final String name, final int age) = _Person; }
genericArgumentFactories
JsonSerializable
のgenericArgumentFactories
の有効/無効を設定します。
デフォルトはfalse
です。
fromJson(Map json) => _$ExampleFromJson(json)
を
fromJson(Map<String, Object?> json, T Function(Object?) fromJsonT) => _$ExampleFromJson(json, fromJsonT)
の様に変更します。
@Freezed(genericArgumentFactories: true) class Example<T> extends _$Example<T> { factory Example({ required T id, }) = _Example; factory Example.fromJson(Map<String, Object?> json, T Function(Object?) fromJsonT) => _$ExampleFromJson(json, fromJsonT); }
の様な定義が出来る様です。
最後に
いかがでしたでしょうか?
今まで使ったことがないオプションはありましたか?
是非触ってみて、Freezed
の手触り感を体験してみてださい!
Twitterフォローお願いします
「次回以降も記事を読んでみたい!」「この辺分からなかったから質問したい!」
そんな時は、是非Twitter (@daiki1003)やInstagram (@ashdik_flutter)のフォローお願いします♪
Twitterコミュニティ参加お願いします
Twitterコミュニティ「Flutter lovers」を開設しました!参加お待ちしております😁
☕️ Buy me a coffee
また、記事がとても役に立ったと思う人はコーヒーを奢っていただけると非常に嬉しいです!
コメント