# Named types

Most of a program's types are named types: a built-in representation, a name
that says what the value means, and the rules a valid value must follow.

```jadpo
type Stock = Int {
    min: 0
}

type Quantity = Int {
    min: 1
    max: 1000
}

type ProductName = Text {
    min_length: 1
    max_length: 120
}

type OrderId = Uuid {}
```

`OrderId` has no rules, but it is still its own type: an `OrderId` can't be
passed where another UUID-based type is expected. Every `type` declaration
creates a new type. There are no aliases, names that are just another way of
writing an existing type.

A named type can build on another named type and add rules. The new type
keeps every rule of the one it builds on, so it can be used wherever that
type is expected. The other way round needs a construction, which checks the
extra rules.

```jadpo
type ProductName = Text {
    min_length: 1
    max_length: 120
}

type ShortProductName = ProductName {
    max_length: 40
}

function catalogue_name(name: ShortProductName) -> ProductName {
    return name
}
```

## Constraints

| Constraint | For | Value | Meaning |
|---|---|---|---|
| `min`, `max` | `Int`, `Decimal` | number | Inclusive bounds |
| `min_length`, `max_length` | `Text`, `Bytes`, `List<T>`, `Set<T>`, `Map<K, V>` | whole number | Inclusive bounds; text counts Unicode characters, collections count items |
| `pattern` | `Text` | string | A regular expression the text must match |
| `format` | `Text` | `email` | The text must be an email address |
| `dimensions` | a type built on `Vector` | whole number, 1 to 16,000 | Exactly that many items ([AI types](/docs/ai-types.md)) |
| `distance` | a type built on `Vector` | a `VectorDistance`: `cosine` (the default), `euclidean` or `inner_product` | How its vectors are compared: `ai.distance` and its index follow it ([Storing a vector](/docs/embeddings-and-search.md#storing-a-vector)) |

Each constraint is written `name: value`, one per line. There are no other
constraints and no custom validation functions.

A refinement, a type that builds on another, can only add to the rules it
inherits. These are errors:

- `type.constraint_contradiction`: a `max` below an inherited `min`, or the
  other way round, and the same for lengths and durations. It is also a
  `Decimal` refinement whose `scale` differs from the one it inherits, since
  the scale decides how the value is stored and sent; a currency other than
  the one it inherits, in a `Money` type's `currency:` or a rate type's
  `from:` and `to:`; and a vector type's `dimensions:` other than the one it
  inherits or outside its lengths.
- `type.constraint_loosened`: a bound looser than the one it inherits, such
  as `max_length: 50` on a type with `max_length: 40`.

The same rules hold for the settings on the fields of every type with
fields, entities and events included. The settings that only an entity's or
an event's fields take (`generated`, `on_delete`, `unique`, `immutable`,
`role`, `personal`, `erase`, `retention`) are described with those
features, starting at [Entities, stores and migrations](/docs/data.md).

An exact number holds at most 38 digits, and a number literal with more is
`type.invalid_literal`.

## Units and money in plain numbers

A type named for a unit but built on a plain number, such as
`type Grams = Int {}`, holds a weight that nothing knows is a weight: a
value in kilograms passes for one in grams, and it adds to a price. The
standard types keep the unit with the number: `Mass`, `Length` and the
other [physical quantities](/docs/physical-quantities.md),
`Duration`, `Money` and `Percentage`. So a type built on `Int` or
`Decimal`, directly or through another type, whose whole name is one of
their units is `type.unit_as_number`, which names the standard type:

| The whole name is | It holds |
|---|---|
| A quantity's unit, by its name or a code of two letters or more: `Grams`, `Metres`, `NauticalMiles`, `Kg`, `Kwh` | That quantity: `Mass`, `Length`, `Energy` |
| `Ms`, `Millis`, `Milliseconds`, `Seconds`, `Secs`, `Minutes`, `Mins` or `Hours` | `Duration` |
| A currency's minor unit: `Pence`, `Penny` or `Cents` | `Money` |
| `Percent` or `Pct` | `Percentage` |

A plural matches as its singular. The words are the data `jadpo
suggest`'s `name` signal reads ([Signals](/docs/signals.md)), so the
two never disagree. A unit that is also a currency's name, `Pounds`, names
both types: `Mass` for a weight, `Money` for an amount of money. A
currency's other major units (`Dollars`, `Euros`) are no unit, so they
are left alone. A name with more in it, such as `PricePence` or
`WeightGrams`, is left to `jadpo suggest`, which reports it as a `name`
finding. Build the type on the standard type instead, named for what it
holds:

```jadpo
/// What a parcel weighs, up to the courier's limit.
type ParcelWeight = Mass {
    max: 30kg
}
```

A name can be a unit by chance: the `Knots` scouts tie are no speed. The
rule is a judgement call, so you can decline it on the type with a reason
([Declining a judgement call](/docs/declining-a-judgement-call.md)):

```jadpo
/// Knots the scouts can tie.
decline type.unit_as_number: "Knots the scouts can tie, not a speed"
type Knots = Int {
    min: 0
}
```
