# When one type can stand in for another

A value can be used where its own type is expected, and where a type it
widens to is expected. Widening means stepping from a type to the more
general one it was declared from. Going the other way always goes through a
constructor. With `Customer` and `Supplier` entities that each have an
`email: Email` field:

| You have | Where `Customer.email` is expected | Where `Email` is expected | Where `Text` is expected |
|---|---|---|---|
| `Customer.email` | yes | yes, it widens | no |
| `Supplier.email` | no | yes, it widens | no |
| `Email` | only through `Customer.email(...)` | yes | no |
| `Text` | only through `Customer.email(...)` | only through `Email(...)` | yes |

- **Widening** follows declared steps only: a field type to its declared type,
  a named type to the named type it builds on.
- **No silent narrowing.** Going from a general type to a specific one always
  goes through a constructor, which re-checks the rules.
- **Same shape is not same type.** Two objects with identical fields are still
  different types.
- **Nothing unwraps.** A named type never becomes its built-in
  representation, except where arithmetic and comparison operators work on
  it.

`Customer.id` and `Supplier.id` stay distinct even when both are version 4
UUIDs. A function that genuinely accepts either takes an enum whose
variants carry each one, which keeps the choice explicit. Your own code has
no generics or unions ([Generic code](generic-code.md)).
