Type aliases
`type Name = Other` names an existing type rather than declaring a new one, and the two names are freely interchangeable - there is no separate `alias` keyword.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
type Name { ... } declares a new type; type Name = Other names an existing one. There is no alias keyword,
because naming a type is not a different kind of declaration from making one - both start with type, and which one
follows tells them apart.
Example#
type EntityId = Int
type Pair<Value> = (Value, Value)
fn process(id: EntityId): Int {
id + 1
}
const raw: Int = 5
print process(raw)
const bounds: Pair<Int> = (1, 2)
print boundsSyntax#
type Name = Other an alias for an existing type
type Name<Params> = Other a generic alias
public type Name = Other exported from its fileRules#
The right side of
type X =is a type position, the same position a:annotation or awithlist uses.const/varhave no meaning there and are not written.An alias is transparent: the alias and its target are the same type, freely interchangeable.
processabove takes anEntityId; passing a plainIntwhererawis declared type checks without a conversion.An alias can be generic.
Pair<Value>above stands for(Value, Value), andPair<Int>is(Int, Int)wherever it is used.An alias is an ordinary scoped name: private to its file unless
public, importable, and it can shadow a prelude name like any other name a file declares.type Int = Int32 const count: Int = 5 print countA declared type has no target; only
type X =has one.type EntityId { value: Int }is a new type with one field namedvalue, not an alias forInt- see Distinct types for what that form is for.
What this is not#
An alias is not a distinct type. Nothing stops an Int from being passed where an EntityId is expected, or the
other way around - the two names never disagree, because they name the same type.
type EntityId = Int
fn process(id: EntityId): Int {
id + 1
}
print process(5)type EntityId = Int
fn process(id: EntityId): Int {
id + 1
}
print process("five")
// error: Expected `EntityId (Int64)`, found `String`The error above names the alias together with its target, EntityId (Int64), where the type was written as the alias:
the annotation of a binding, a parameter of a function, and a name bound with one of those. Everywhere else - a type
that a message works out rather than reads off an annotation - it is the target alone, because the checker holds the
alias for the message only and never in the type itself. The aliases of the standard library (Int, Float) are
not repeated: Int64 is how every message spells an integer.
Shadowing a prelude name is not rejected, even though it can be confusing. type Int = Int32 in rule 4 compiles;
nothing in the compiler warns that literals are still Int64 regardless (see Integers), so a file
that shadows Int this way is easy to misread.
Related#
- Distinct types - a single-field type, for when an alias should not be interchangeable.
- Integers - why an integer literal's type does not follow an alias like
Int. - Literal types -
type Name = "a" | "b", the same declaration form for a different right side.