# Types as Specification in Elixir with Domo library
<p align="center">
<a href="https://livebook.dev/run?url=https%3A%2F%2Fgist.github.com%2FIvanRublev%2Fc8dcb87068ffe4f35518cb97ca65cc27">
<img src="https://livebook.dev/badge/v1/blue.svg" alt="Run in Livebook" />
</a>
</p>
```elixir
Mix.install([:domo])
```
https://hex.pm/packages/domo
## Define the struct type enriched with precondition
```elixir
defmodule Guardian do
use Domo, skip_defaults: true
defstruct [:name]
@type t :: %__MODULE__{name: String.t()}
end
defmodule User do
use Domo, skip_defaults: true
defstruct [:name, :age, :address, :guardian]
@type str :: String.t()
@type t :: %__MODULE__{
name: str(),
age: integer(),
address: str(),
guardian: Guardian.t() | nil
}
precond(
t:
&cond do
&1.age < 18 and is_nil(&1.guardian) ->
{:error, "Users under 18 must have guardian."}
&1.age >= 18 and not is_nil(&1.guardian) ->
{:error, "Users of age 18 and over must have no guardian."}
true ->
:ok
end
)
end
```
## Shared structure proofs allowed use cases by itself 💯
```elixir
User.new(name: "Junior", age: 8, address: "Somestr. 14", guardian: nil)
```
<!-- livebook:{"output":true} -->
```
{:error, [t: "Users under 18 must have guardian."]}
```
```elixir
ok_junior =
User.new(name: "Junior", age: 8, address: "Somestr. 14", guardian: Guardian.new!(name: "John"))
```
<!-- livebook:{"output":true} -->
```
{:ok, %User{address: "Somestr. 14", age: 8, guardian: %Guardian{name: "John"}, name: "Junior"}}
```
```elixir
{:ok, junior} = ok_junior
User.ensure_type(%{junior | age: 18})
```
<!-- livebook:{"output":true} -->
```
{:error, [t: "Users of age 18 and over must have no guardian."]}
```
```elixir
User.ensure_type(%{junior | age: 18, guardian: nil})
```
<!-- livebook:{"output":true} -->
```
{:ok, %User{address: "Somestr. 14", age: 18, guardian: nil, name: "Junior"}}
```