Skip to content

Type Relations

Type hierarchy

For numeric types, a narrower type can be assigned to a wider one

Record

unknown

Custom model with properties

Array

Tuple

numeric

integer

int8

int16

int32

safeint

int64

uint8

uint16

uint32

uint64

float

float32

float64

decimal

decimal128

string

boolean

null

bytes

plainDate

plainTime

zoneDateTime

duration

Model with properties

When determining if type S can be assigned to type T, if T is a model with properties, it checks whether all those properties are present in S and if their types can be assigned to the type of the corresponding property in T.

For instance,

model T {
foo: string;
bar: int32;
}
// Valid
model S { // When properties types are the exact same
foo: string;
bar: int32;
}
model S { // When the properties types are literal assignable to the target type
foo: "abc";
bar: 123;
}
model S {
foo: string;
bar: int8; // int8 is assignable to int16
}
model S {
foo: string;
bar: int32;
otherProp: boolean; // Additional properties are valid.
}
// Invalid
model S { // Missing property bar
foo: string;
}
model S {
foo: string;
bar: int64; // int64 is NOT assignable to int32
}

Record<T>

A record is a model indexed with a string with a value of T. It represents a model where all properties (string keys) are assignable to the type T. You can assign a model expression where all the properties are of type T or another model that is also a Record<T>.

// Represent an object where all the values are int32.
alias T = Record<int32>;
// Valid
alias S = {
foo: 123;
bar: 345;
};
alias S = {
foo: int8;
bar: int32;
};
model S is Record<int32>;
model S is Record<int32> {
foo: 123;
}
// Invalid
alias S = {
foo: "abc";
bar: 456;
};
alias S = {
foo: int64;
bar: int32;
};
model S {
foo: 123;
bar: 456;
}

Why isnโ€™t the last case assignable to Record<int32>?

In this scenario,

alias T = Record<int32>;
model S {
foo: 123;
bar: 456;
}

The reason why model S is not assignable, but the model expression { foo: 123; bar: 456; } is, is because model S could be extended with additional properties that might not be compatible.

For instance, if you add a new model,

model Foo is S {
otherProp: string;
}

Here, Foo is assignable to S following the model with property logic, and if S was assignable to Record<int32>, Foo would also be passable. However, this is now invalid as otherProp is not an int32 property.