Hi! Is it possible to make have a @type
for a map, with specific keys, that’s composed out of smaller pieces for the sake of readability and/or reuse?
For example, say you wanted to chop up a map:
@type user() :: %{
id: String.t(),
full_name: String.t(),
birth_year: non_neg_integer(),
}
… into smaller pieces, that can be used to ‘build’ up a larger structure, like:
@type personDetails() :: %{ full_name: ..., birth_year: ... }
@type hasId :: %{ id: String.() }
# (I'm borrowing JS / Flow's syntax for this.)
@type user() :: %{
...hasId(), # the 'id' field from this type,
...personDetails(), # the 'full_name' and 'birth_year' from this type,
created_at: NaiveDateTime.t() # … and this extra field while we're at it.
}
This faculty exists in a few typed languages with structurally-typed ‘records’, like TypeScript, Flow, Elm and PureScript; It’s known in at least the first two as ‘intersections’ (as counter operation to ‘unions’) and in the latter two as ‘extensible records’.
(I know that I can have a ‘nested’ composition, by having something like @type user :: %{ identification: hasId(), person: personDetails() }
, but I’m interested in ‘sibling’ or ‘flat’ composition.)
My motivations for this is partly describing a struct used for DB interaction, partly for describing a union where each option is made up of some common fields, and partly a mix of situations where being able to re-use parts of a map like this would have aided reuse and avoided ‘copy-paste’-style definition drift.
(Thanks!)