Shared Properties

Let's continue with our Weather example (you can find it here).

Define a Shared Property

In freezed, when a property is defined on all constructors, it is automatically considered as being a shared property.

For modddels, you should explicitly define shared properties this way :

@Modddel(
  // validationSteps: [...],
  sharedProps: [
    SharedProp('int', 'temperature'),
  ],
)

As you can see, you provide an array of SharedProp. Inside the SharedProp, you provide the type and the name of the shared property (which should be common to all factory constructors).

Now, you can directly access the temperature property from the super-sealed classes ValidWeather, InvalidWeather and InvalidWeatherValue, without case-modddels pattern matching :

// before :
final temperature = validWeather.mapWeather(
    sunny: (validSunny) => validSunny.temperature,
    rainy: (validRainy) => validRainy.temperature,
);

// after
final temperature = validWeather.temperature;

If you want to directly access the temperature property from the Weather super-sealed class too, temperature should first be accessible from the case-modddels Sunny and Rainy. Which means that it should be annotated with @withGetter in both factory constructors :

Now you can do :

Rules to keep in mind

Using a common supertype

The type of the shared property doesn't have to be the same in all factory constructors. Rather, the type specified inside the SharedProp should be a common supertype.

For example :

As you can see, num is a common supertype of double and int, and String? is a common supertype of String and String?.

Shared Properties and Param Transformations

The param transformations (valid, null and non-null) accross the different case-modddels are taken into account for narrowing the type of the shared property in the different super-sealed classes.

For example : Let's say we have this User SimpleEntity :

In this example, User is a union of two SimpleEntities : AppUser and Moderator. They have two shared properties : username and age. Username is a union of two ValueObjects : NormalUsername and ModeratorUsername. Age is a ValueObject.

This table represents the types of these two shared properties in the different super-sealed classes :

property
User
InvalidUserEarly
InvalidUserMid
ValidUser

username

Username?

Username?

Username

ValidUsername

age

Age?

Age?

Age

ValidAge

For username :

  • The type of username becomes non-nullable in InvalidUserMid, because at that point username is not null in the two case-modddels (InvalidAppUserMid and InvalidModeratorMid) : the two NullFailures have been processed in the previous validationStep.

  • The type of username becomes valid (ValidUsername) in ValidUser, because at that point username is valid in the two case-modddels (ValidAppUser and ValidModerator) : the contentValidation has been processed in the previous validationStep.

For age :

  • The type of age becomes non-nullable in InvalidUserMid, because at that point age is not null in the two case-modddels :

    • In InvalidAppUserMid : age was already non-nullable.

    • In InvalidModeratorMid : the NullFailure has been processed in the previous validationStep.

  • The type of age becomes valid (ValidAge) in ValidUser, because at that point age is valid in the two case-modddels :

    • In ValidAppUser : age was already valid, because it's annotated with @validParam.

    • In ValidModerator : the contentValidation has been processed in the previous validationStep.

This example only showcases the Valid and Non-null param transformations, but it works the same way for Null param transformations : If a shared parameter becomes 'Null' in all case-modddels, then it becomes 'Null' in the appropriate super-sealed class.

Disabling Param Transformations for a Shared Property

Sometimes, you may want to disable a certain kind of param transformation for a shared property.

You can do so easily :