# Packages use the standard types

When you declare a type with the same shape as a standard type, the
compiler reports the error `type.standard_exists` and points you at the
standard type. It does this in a package's public types (the ones
`surface.jadpo_record` lists) and in your app's own code alike, because
an app's `Location { lat, lng }` reaches its API and its tables exactly
as a package's would. You can
[decline](declining-a-judgement-call.md) it,
so a type with a genuinely different meaning is kept, with a reason on
its declaration.

The check matches by shape and by the common names for each field, not by
exact names. It matches an `Object` declaration whose only fields are
those in the table below, in any order, none of them optional (`T?`).

Only distinctive shapes match, to keep false matches rare across hundreds
of types. A shape matches when it has:

- at least two fields;
- at least one field name that belongs to the domain rather than being
  generic: `latitude`, `currency` and `iban` count, but `name`, `value`,
  `id`, `code`, `type` and `text` don't;
- field types that line up with the standard's, such as numbers for
  coordinates, or text or an enum for a currency;
- no fields beyond those.

Single-value types never match by shape. A declaration with a standard
type's name is already an error, and a differently named `Text` says
nothing about what it holds.

| Standard type | Matches an `Object` whose only fields are |
|---|---|
| `Point` | a latitude (`latitude`, `lat`) and a longitude (`longitude`, `lng`, `lon`, `long`), both built on `Int` or `Decimal` |
| `Money` | an amount (`amount`, `value`, `amount_minor`, `minor`, `cents`, `pence`) built on `Int` or `Decimal`, and a currency (`currency`, `currency_code`) built on `Text` or an enum |
| `InstantRange` | a start (`start`, `starts_at`, `start_at`) and an end (`end`, `ends_at`, `end_at`), each built on `Instant` |
| `Colour` | `r`, `g`, `b` and optionally `a`, or `red`, `green`, `blue` and optionally `alpha`, built on `Int` or `Decimal` |
| `LineString`, `Polygon` | a list of a type that itself matches `Point` (`points`, `coordinates`), and nothing else |

The other vocabulary types are single values (`Email`, `Country`,
`PhoneNumber`), where a shape says nothing, so a package's
`type Iso2 = Text { pattern: "[A-Z]{2}" }` isn't flagged.

Here is the error for a package that declares its own point:

```text
error: `GeoPoint` is the standard `Point` under another name
 --> types/geo_point.jadpo:3:13
  |
3 | public type GeoPoint = Object {
  |             ^^^^^^^^ a latitude and a longitude
  reason: `GeoPoint` has only a latitude (`lat`) and a longitude (`lng`), which is the standard `Point`. Packages that each declare their own disagree on order and on names, and an app has to convert between them.
  next: Use `Point` in the package's public types, converting at the edge with `geo.from_lat_lng` or `geo.from_lng_lat` where the provider sends a pair, or write `decline type.standard_exists: "<why>"` above it if this is deliberate (agent)
  rule: type.standard_exists
  help: https://jadpo.dev/docs/errors/type.standard_exists
```

The error stops `check` and the build until you do one of two things.

## Swap to the standard type

For a type not yet stored or on the wire, the fix makes the swap in one
step, and an agent may apply it: `jadpo fix <name> swap`, or the editor's
quick fix ([A release that adds a standard type](standard-type-clashes.md)).
Where the provider sends another form, convert at the edge, in a
package's `wire:` or `decode:`.

For a type already stored or in an API record, the fix writes the edit
and the data migration, and the change goes through the existing
`ApiChange` and `DataChange` [acceptances](acceptances.md).

## Decline, with a reason, on the type itself

Write the usual [decline line](declining-a-judgement-call.md#writing-a-decline)
directly above the declaration:
`decline type.standard_exists: "Grid squares, not WGS84 degrees"`. An
agent or a person may decline. `jadpo approval` lists every decline with
its reason, so declining by reflex shows in review.

## False matches

The cost of matching by shape is false matches: an `Object` of `x` and
`y` grid cells, or an `amount` and `currency` that are a quote rather
than money, matches. The required reason handles them, and review sees
each one.

## Where the error is reported

The error above is a package's. `jadpo package check` reports it in a
package's own repository, and `jadpo check` reports it for an installed
package or your app's own integration, on its `public` types only. A type
a package keeps to itself is the shape it decodes from
([Decoding](decoding.md)). On your app's code the error
reads as under [Errors](standard-library.md#errors).

`Colour`'s alpha is the first field a shape lets an `Object` leave out.
`LineString` and `Polygon` match through a list, which is one shape, so
the error names both ([Interop](geospatial-interop.md); its example is
under [Errors](standard-library.md#errors)).

## Reference lists ship with Jadpo

The `Country`, `Language` and `PhoneNumber` lists ship with each Jadpo
release, as the time-zone database does. Fixed reference data is declared
in the release, as these enums, not by applications.

Not built yet: the data migration and the acceptances for swapping a type
already stored or on the wire come with
[Records and manifest](records-and-manifest.md), and until then such a
swap stops.
