2022/7/13/freezed/Readme-translation

 

freezedのライセンスページ

MIT License

Copyright (c) 2020 Remi Rousselet

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

freezed 2.0.5

Welcome to Freezed, yet another code generator for data-classes/unions/pattern-matching/cloning.

Freezedへようこそ。データクラス/unions/pattern-matching/cloningのコード生成用パッケージ。


Motivation

Dart is awesome, but defining a “model” can be tedious. We may have to:

Dartf素晴らしいですが、モデルクラスを定義するのは少し面倒ですね。下記のことをする必要があります。

  • define a constructor + the properties
  • override toString, operator ==, hashCode
  • implement a copyWith method to clone the object
  • handling de/serialization

 

  • コンストラクタとプロパティの宣言
  • toString, operator == , hashCodeのオーバーライド
  • オブジェクトをコピー(プロパティの値が同じな別のオブジェクトの生成)するためのcopyWithメソッドの実装
  • serialization/deserialization用コードの定義

 

On top of that, Dart is also missing features such as union types and pattern-matching.

さらにDartはunion typesとpattern-matchingの機能を欠いています。

 

Implementing all of this can take hundreds of lines, which are error-prone and the readability of your model significantly.

これらをすべて実装すると数百行になり、エラーが発生しやすく、モデルの可読性も著しく低下します。

 

Freezed tries to fix that by implementing most of this for you, allowing you to focus on the definition of your model.

Freezedは、このような問題を解決するために、モデルの定義に集中できるように、そのほとんどを実装しています。


Before

@immutable
class Person{
  const Person({
    required this.firstName,
    required this.lastName,
    required this.age,
});

  final String firstName;
  final String lastName;
  final int age;

  factory Person.fromJson(Map<String, Object?> json){
    return Person(
      firstName: json['firstName'] as String,
      lastName: json['lastName'] as String,
      age: json['age'] as int,
    );
  }

  Map<String, Object?> toJson(){
    return {
      'firstName': firstName,
      'lastName': lastName,
      'age': age,
    };
  }

  Person copyWith({
    String? firstName,
    String? lastName,
    int? age,
}){
    return Person(
      firstName: firstName, //compile error
      lastName: lastName, //compile error
      age: age, //compile error
    );
  }

  @override
  String toString(){
    return 'Person('
        'fristName: $firstName,'
        'lastName: $lastName,'
        'age: $age'
        ')';
  }

  bool operator ==(Object other){
    return other is Person &&
        other.runtimeType == runtimeType &&
        other.firstName == firstName &&
        other.lastName == lastName &&
        other.age == age;
  }

  @override
  int get hashCode{
    return Object.hash(
      runtimeType,
      firstName,
      lastName,
      age,
    );
  }
}

 


after

@freezed
class Person with _$Person{
  const factory Person({
    required String firstName,
    required String lastName,
    required int age,
  }) = _Person;

  factory Person.fromJson(Map<String, Object?>)=> _PersonFromJson(json);
}

 


How to use

To use Freezed, you will need your typical build_runner/code-generator setup.

Freezedを使用するには、build_runner/code generatorのセットアップが必要です。

 

First, install build_runner and Freezed by adding them to your pubspec.yaml file:

まずbuild_runnerFreezedをpubspec.yamlファイルに追加してインストールします。

 

If you are using creating a Flutter project:

Flutterプロジェクトの場合は、

flutter pub add freezed_annotation
flutter pub add --dev build_runner
flutter pub add --dev freezed
# if using freezed to generate fromJson/toJson, also add:
flutter pub add json_annotation
flutter pub add --dev json_serializable

 

Dartプロジェクトの場合は、

dart pub add freezed_annotation
dart pub add --dev build_runner
dart pub add --dev freezed
# if using freezed to generate fromJson/toJson, also add:
dart pub add json_annotation
dart pub add --dev json_serializable

 

This installs three packages:

この作業で三つのパッケージをインストールします。

build_runner、コード自動生成用ツールです。

freezed、コード生成。

freezed_annotation、freezedのアノテーションに関することを含むパッケージ。

 

Disabling invalid_annotation_target warning and warning in generates files.

工事中🏗

 


Run the generator

To run the code generator, execute the following command:

コードの自動生成を実行するには、下記のコマンドを実行します。

dart run build_runner build

 

For Flutter projects, you can also run:

Flutterの場合は下記のコマンドを実行します。

flutter pub run build_runner build

 

Note that like most code-generators, Freezed will need you to both import the annotation (freezed_annotation) and use the part keyword on the top of your files.

他のほとんどのコード生成と同様に、Freezedも

アノテーション(freezed_annotation)のインポート

と、

partキーワードの使用

があなたのファイルの先頭で必要になります。

 

As such, a file that wants to use Freezed will start with:

ということで、Freezedを使用する場合下記のようなコードでスタートすることになります。

import 'package:freezed_annotation/freezed_annotation.dart';

part 'my_file.freezed.dart';

 

CONSIDER also importing package:flutter/foundation.dart.

package:flutter/foundation.dartをインポートすることを検討してください。

 

The reason being, importing foundation.dart also imports classes to make an object nicely readable in Flutter’s devtool.

なぜなら、foundation.dartをインポートすることで、Flutterのdevtoolでオブジェクトをきれいに読めるようにするためのクラスもインポートされるからです。

 

If you import foundation.dart, Freezed will automatically do it for you.

foundation.dartをインポートすれば、Freezedが自動的にやってくれます。


Creating a Model using Freezed

An example is better than a long abstract explanation, so here’s a typical Freezed class:

長い抽象的な説明よりも例があったほうがいいので、ここで通常のFreezedのクラスを紹介します。

 

// This file is "main.dart"
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';

// required: associates our `main.dart` with the code generated by Freezed
// 必須: Freezedで生成されたコードとmain.dartは関連付ける。
part 'main.freezed.dart';
// optional: Since our Person class is serializable, we must add this line.
// オプショナル: Personクラスがシリアライズ可能な場合下記のコードを追加する必要があります。
// But if Person was not serializable, we could skip it.
//Personクラスがシリアライズ可能でない場合、スキップできます。
part 'main.g.dart';

@freezed
class Person with _$Person {
  const factory Person({
    required String firstName,
    required String lastName,
    required int age,
  }) = _Person;

  factory Person.fromJson(Map<String, Object?> json)
      => _$PersonFromJson(json);
}

 

The following snippet defines a model named Person:

次のスニペットは、Personという名前のモデルを定義しています。

 

  • Person has 3 properties: firstName, lastName and age

PersonクラスはfirstName、lastName、ageの三つのプロパティを持ちます。

 

  • Because we are using @freezed, all of this class’s properties are immutable.

@freezedアノテーションを使っているので、このクラスのプロパティは全てimmutableです。

(immutable = クラスのフィールドが全てfinalである、ということ)

 

  • Since we defined a fromJson, this class is de/serializable. Freezed will add a toJson method for us.

fromJsonを定義していますので、このクラスはシリアライズ/デシリアライズ可能です。Freezedは私たちの代わりにtoJsonメソッドも追加してくれます。

 

Freezed will also automatically generate:

Freezedは自動的に下記のものも生成してくれます。

 

  • a copyWith method, for cloning the object with different properties

copyWithメソッド、オブジェクトの一部のプロパティを上書きしたオブジェクトを生成する。

 

  • a toString override listing all the properties of the object

toStringメソッドのオーバーライド、オブジェクトの全てのプロパティを並べて表示する。

 

  • an operator == and hashCode override (since Person is immutable)

operator == とhashCodeのオーバーライド(Personクラスはimmutableだから)

 

From this example, we can notice a few things:

このサンプルから、私たちはいくつかのことに注目することができます。

 

  • It is necessary to annotate our model with @freezed (or @Freezed/@unfreezed, more about that later).
    This annotation is what tells Freezed to generate code for that class.

私たちのモデルクラスを@freezed (あるいは@Freezed / @unfreezed 、後に説明あり)でアノテーションする必要があります。

このアノテーションによりFreezedに対して、このクラスを生成することを指示します。

 

  • We must also apply a mixin with the name of our class, prefixed by _$. This mixin is what defines the various properties/methods of our object.

クラス名の前に_$をつけたmixinをミックスインする必要があります。このmixinは私たちのオブジェクトの全てのプロパティ/メソッドを定義するものです。

 

  • When defining a constructor in a Freezed class, we should use the factory keyword as showcased (const is optional).
    The parameters of this constructor will be the list of all properties that this class contains.
    Parameters don’t have to be named and required. Feel free to use positional optional parameters if you want!

Freezedクラスの中でコンストラクタを宣言する時は、factoryキーワードを使う必要があります。(constキーワードはオプショナルです。)

コンストラクタのパラメータは、このクラスが含む全てのプロパティです。

工事中🏗

 


Defining a mutable class instead of an immutable one

So far, we’ve seen how to define a model where all of its properties are final; but you may want to define mutable properties in your model.

ここまで私たちは、全てのプロパティがfinalなモデル(クラス)の定義方法について見てきました。しかし、モデル(クラス)の中にmutableなプロパティを宣言したい場合もあるかもしれません。

 

Freezed supports this, by replacing the @freezed annotation with @unfreezed:

Freezedはこれをサポートしています。@freezedアノテーションの代わりに@unfreezedアノテーションを使用してください。

 

@unfreezed
class Person with _$Person {
  factory Person({
    required String firstName,
    required String lastName,
    required final int age,
  }) = _Person;

  factory Person.fromJson(Map<String, Object?> json)
      => _$PersonFromJson(json);
}

This defines a model mostly identical to our previous snippets, but with the following differences:

これはimmutableなケースとほとんど同じですが、下記の点で違いがあります。

 

firstName and lastName are now mutable. As such, we can write:

firstNameとlastNameはmutableなので、私たちは下記のように書くことができます。

void main() {
  var person = Person(firstName: 'John', lastName: 'Smith', age: 42);

  person.firstName = 'Mona';
  person.lastName = 'Lisa';
}

 

  • age is still immutable, because we explicitly marked the property as final.

ageプロパティについては明示的にfinalで宣言しているので、ageプロパティはimmutableです。

 

Person no-longer has a custom ==/hashCode implementation:

Personクラスは==/hashCodeの実装を持っていません。

void main() {
  var john = Person(firstName: 'John', lastName: 'Smith', age: 42);
  var john2 = Person(firstName: 'John', lastName: 'Smith', age: 42);

  print(john == john2); // false
}

 

  • Of course, since our Person class is mutable, it is no-longer possible to instantiate it using const.

Personクラスはnutableですので、当然constキーワードを使ってインスタンス化することはできません。


Allowing the mutation of Lists/Maps/Sets

By default when using @freezed (but not @unfreezed), properties of type List/Map/Set are transformed to be immutable.

工事中🏗

 

This means that writing the following will cause a runtime exception:

これは、下記のように書くと実行時に例外が発生することを意味します。

@freezed
class Example with _$Example {
  factory Example(List<int> list) = _Example;
}

void main() {
  var example = Example([]);
  example.list.add(42); // throws because we are mutating a collection
}

 

That behavior can be disabled by writing:

この挙動は下記のように書けば無効化することができます。

@Freezed(makeCollectionsUnmodifiable: false)
class Example with _$Example {
  factory Example(List<int> list) = _Example;
}

void main() {
  var example = Example([]);
  example.list.add(42); // OK
}

 


How copyWith works

As explained before, when defining a model using Freezed, then the code-generator will automatically generate a copyWith method for us.

前述した通り、Freezedを使ってモデルを定義すると、コード自動生成は自動的にcopyWithメソッドを私たちの代わりに生成します。

 

This method is used to clone an object with different values.

このメソッドは異なる値でオブジェクトをクローンするのに使われます。

(上書きしたい値を引数として渡して、該当フィールドをその値で上書きした別のオブジェクトを返す。)

 

For example if we define:

例えば下記のように定義したとします。

@freezed
class Person with _$Person {
  factory Person(String name, int? age) = _Person;
}

 

Then we could write:

void main() {
  var person = Person('Remi', 24);

  // `age` not passed, its value is preserved
  // `age`は渡されていないので、24が使われます。
  print(person.copyWith(name: 'Dash')); // Person(name: Dash, age: 24)
  
  // `age` is set to `null`
  // `age`は`null`がセットされます。
  print(person.copyWith(age: null)); // Person(name: Remi, age: null)
}

 

Notice Freezed supports person.copyWith(age: null).

Freezedがperson.copyWith(age: null)をサポートしていることに注目してください。


Going further: Deep copy

While copyWith is very powerful in itself, it starts to get inconvenient on more complex objects.

copyWithはそれ自体非常に強力ですが、より複雑なオブジェクトになると不便になってきます。

 

Consider the following classes:

下記のクラスについて考えみましょう。

@freezed
class Company with _$Company {
  factory Company({String? name, required Director director}) = _Company;
}

@freezed
class Director with _$Director {
  factory Director({String? name, Assistant? assistant}) = _Director;
}

@freezed
class Assistant with _$Assistant {
  factory Assistant({String? name, int? age}) = _Assistant;
}

 

Then, from a reference on Company, we may want to perform changes on Assistant.
For example, to change the name of an assistant, using copyWith we would have to write:

そして、Companyの参照から、Assistantの変更を実行したい場合があります。
例えば、アシスタントの名前を変更するには、copyWithを使用して、次のように記述する必要があります。

 

Company company;

Company newCompany = company.copyWith(
  director: company.director.copyWith(
    assistant: company.director.assistant.copyWith(
      name: 'John Smith',
    ),
  ),
);

This works, but is relatively verbose with a lot of duplicates.
This is where we could use Freezed‘s “deep copy”.

これで期待通りの結果になりますが、しかしこれでは冗長で、コードの重複が多いですね。

これがFreezedの”deep copy”が存在する理由です。

 

If a Freezed model contains properties that are also Freezed models, then the code-generator will offer an alternate syntax to the previous example:

Freezedモデルが同じくFreezedモデルであるプロパティを持つ場合、コードジェネレーターは前の例の代わりの構文を提供します。(それによって下記のように書くことが可能)

Company company;

Company newCompany = company.copyWith.director.assistant(name: 'John Smith');

 

This snippet will achieve strictly the same result as the previous snippet (creating a new company with an updated assistant name), but no longer has duplicates.

このスニペットは一つ前の例のスニペットと全く同じ結果となります(assistantの名前を更新した新いcompanyを生成する)、しかしコードの重複が無くシンプルです。

 

Going deeper in this syntax, if instead, we wanted to change the director’s name then we could write:

代わりにdirectorの名前を変更したい場合、私たちは下記のように書くことができます。

Company company;
Company newCompany = company.copyWith.director(name: 'John Doe');

 

Overall, based on the definitions of Company/Director/Assistant mentioned above, all the following “copy” syntaxes will work:

全体として、上記のCompany/Director/Assistantの定義に基づいて、以下のすべての「コピー」構文が使用可能です。

Company company;

company = company.copyWith(name: 'Google', director: Director(...));
company = company.copyWith.director(name: 'Larry', assistant: Assistant(...));

 


Null consideration

Some objects may also be null. For example, using our Company class, then Director‘s assistant may be null.

いくつかのオブジェクトはnullかもしれません。例えば、上記のCompanyクラスを使って説明すると、Directorのassistantプロパティがnullの可能性がある、ということです。

 

As such, writing below code doesn’t make sense.

そうすると、下記のコードは意味を成さないことになります。

Company company = Company(name: 'Google', director: Director(assistant: null));
Company newCompany = company.copyWith.director.assistant(name: 'John');

 

We can’t change the assistant’s name if there is no assistant to begin with.

もしassistant自体がnullなら、それの名前を変更しようとしても不可能です。

 

In that situation, company.copyWith.director.assistant will return null, causing our code to fail to compile.

このようなシチュエーションでは、company.copyWith.director.assistantがnullを返すので、それによりコンパイルが失敗します。

 

To fix it, we can use the ?.call operator and write:

これを修正するためには、?.call オペレーターを使って下記のように書きます。

Company? newCompany = company.copyWith.director.assistant?.call(name: 'John');

 


Adding getters and methods to our models

Sometimes, you may want to manually define methods/properties in our classes.
But you will quickly notice that if you try to do, then it won’t work.

時には手動でメソッド/プロパティを定義したい時がありますが、下記のようにするとうまくいかないことに気づくと思います。

//bad
@freezed
class Person with _$Person {
  const factory Person(String name, {int? age}) = _Person;

  void method() {
    print('hello world');
  }
}

 

For that to work, we need an extra step: We need to define a private empty constructor:

これをしたい場合は追加のステップが必要です。プライベートな空のコンストラクタを定義する必要があります。

@freezed
class Person with _$Person {
  // Added constructor. Must not have any parameter
  const Person._();

  const factory Person(String name, {int? age}) = _Person;

  void method() {
    print('hello world');
  }
}

 


Asserts

Dart does not allow adding assert(...) statements to a factory constructor.
As such, to add asserts to your Freezed classes, you will need the @Assert decorator:

Dartは、assert( … )文をfactoryコンストラクタに追加することはできません。

assert(確認)をFreezedクラスに追加したい場合は、@Assert 修飾子が必要です。

class Person with _$Person {
  @Assert('name.isNotEmpty', 'name cannot be empty')
  @Assert('age >= 0')
  factory Person({
    String? name,
    int? age,
  }) = _Person;
}

 


Default values

Similarly to asserts, Dart does not allow “redirecting factory constructors” to specify default values.

assertと同様に、Dartはデフォルト値の指定のための”redirecting factory constructors”を認めていません。

 

As such, if you want to specify default values for your properties, you will need the @Default annotation:

プロパティのデフォルト値を指定したい場合は、@Defaultアノテーションを使う必要があります。

class Example with _$Example {
  const factory Example([@Default(42) int value]) = _Example;
}

 


NOTE:
If you are using serialization/deserialization, this will automatically add a @JsonKey(defaultValue: <something>) for you.

工事中🏗

 


Decorators and comments

Freezed supports property and class level decorators/documentation by decorating/documenting their respective parameter and constructor definition.

Freezed は、プロパティとクラスレベルのデコレータ/ドキュメントをサポートしており、それぞれのパラメータとコンストラクタの定義をデコレート/ドキュメント化します。

 

@freezed
class Person with _$Person {
  const factory Person({
    String? name,
    int? age,
    Gender? gender,
  }) = _Person;
}

 

If you want to document name, you can do:

nameフィールドにドキュメントを追加したい場合、下記のようにします。

@freezed
class Person with _$Person {
  const factory Person({
    /// The name of the user.
    ///
    /// Must not be null
    String? name,
    int? age,
    Gender? gender,
  }) = _Person;
}

 

If you want to mark the property gender as @deprecated, then you can do:

genderプロパティを@deprecatedとマークしたい場合、下記のようにします。

@freezed
class Person with _$Person {
  const factory Person({
    String? name,
    int? age,
    @deprecated Gender? gender,
  }) = _Person;
}

 

This will deprecate both:

  • The constructor
    Person(gender: Gender.something); // gender is deprecated
    
  • The generated class’s constructor:
    _Person(gender: Gender.something); // gender is deprecated
    
  • the property:
    Person person;
    print(person.gender); // gender is deprecated
    
  • the copyWith parameter:
    Person person;
    person.copyWith(gender: Gender.something); // gender is deprecated

 

Similarly, if you want to decorate the generated class you can decorate the defining factory constructor.

同様に、もし生成されたクラスを装飾したい場合は、定義されたfactoryコンストラクタを装飾することができます。

 

As such, to deprecate _Person, you could do:

このように、_Personを非推奨とするには、次のようにします。

@freezed
class Person with _$Person {
  @deprecated
  const factory Person({
    String? name,
    int? age,
    Gender? gender,
  }) = _Person;
}

 


次のページ(Part2)へ>>

 

参考

https://pub.dev/packages/freezed

コメントを残す

メールアドレスが公開されることはありません。