Summary#
Types explains the types with a wrinkle. This page is the other half: the complete list, so that "does the language have a type for this?" is a question you can answer by looking rather than by guessing.
It is worth having because guessing goes wrong in a specific way — you invent a name for something that already
exists. There is no Command type for a callable; it is Action. There is no Set<T>; it is HashSet<T>. Every
name below is one the compiler matches, and the list is checked against the compiler itself, so it cannot quietly
fall behind.
Anything not on this page is a type you declare — an entity, an enum, a class, or a component's own type
parameter.
Description#
Scalars and value kinds#
The storable types. These are what an entity member, a function local, or a component parameter may be.
| Type | What it is |
|---|---|
string | Text. default(string) is null, exactly as in C#. |
char | A single character, in single quotes. See char. |
int | A 32-bit integer. |
long | A 64-bit integer. See long. |
double | A double-precision float — measurements, science. |
bool | True or false. |
decimal | Exact base-10 — money, quantities. See decimal. |
DateTime | A date and time. See DateTime. |
DateOnly | A calendar date with no time of day. |
TimeOnly | A time of day with no date. |
TimeSpan | A duration. See TimeSpan (durations). |
Guid | A globally unique id. |
Json | An arbitrary JSON document. |
RichText | Formatted prose, stored as a rich-text document. |
Markdown | A section-addressable markdown document. See Markdown. |
Vector | An embedding, for similarity search; [MaxLength] sets the dimensions. |
Zone | An IANA time-zone token, e.g. Europe/Stockholm. |
Culture | A BCP-47 culture token, e.g. sv-SE. |
A bare member of one of these is required unless the type has an honest zero — see
Optional and required members, which is the rule that decides whether ? is needed.
Which collection types may I write?#
| You write | What it is |
|---|---|
T[] | An array. |
T[][] | A JAGGED array — a collection of collections, which is how you spell a grid. Indexes as g[y][x], on both sides of an assignment. T[,] (rectangular) is not a type here, and the compiler says so and points at this form. |
byte[] | Binary data — the one array form that is a scalar rather than a collection. |
List<T> | An ordered, mutable list. |
HashSet<T> | A set of distinct values. |
Dictionary<K, V> | A keyed map. |
stream<T> | A collection that is still being written. A function returning one produces its results with yield return, and a live var bound to it renders each item as it arrives — see yield — a function that produces results over time. |
An entity's child rows are not one of these — they are a collection property on the parent, described in
relations. Reach for List<T> for an in-memory list, never to hold children.
A jagged array is not a separate kind. T[] is a collection of T, so T[][] is a collection of those —
the same thing List<List<T>> spells, and the two are interchangeable. Write whichever reads better where you are:
int[][] board = []; // a grid, empty
int[][] board = [[1, 2], [3, 4]]; // …or laid out literally
var here = board[y][x]; // read
board[y][x] = 1; // and write⚠ int[,] does not exist. A rectangular array is a distinct type in C# and not one Osy# has; the compiler
refuses it by name and tells you to write int[][], which indexes identically.
How do I type a function value?#
Two spellings, both exactly C#'s, and there are no others:
| You write | What it is |
|---|---|
Action | A callback that takes nothing and returns nothing. |
Action<T…> | A callback that takes arguments and returns nothing. |
Func<T…, TResult> | A callback that returns a value. The last type argument is the return type. |
component PrimaryButton(string label, Action onPress) { … }
class MenuEntry {
public string Label;
public Action Run; // the verb to run — an Action, not a "Command"
}Func with no type argument is an error: a function that returns something must say what. For a callback that
returns nothing, use Action.
Calling one. A callable is invoked exactly as in C# — run() on a local or parameter, entry.Run() on a class
member, and Run() unqualified inside the class that declares it:
class MenuEntry {
public string Label;
public Action Run;
}
component Menu(MenuEntry[] entries, Action onDismiss) {
action Choose(MenuEntry entry) {
entry.Run(); // run the verb the caller put on this entry
onDismiss(); // and the callback this component was given
}
…
}The argument count and types are checked against the callable's signature, so Action<int> invoked with a string is
a compile error rather than a surprise on the client.
A verb call evaluates to nothing. It is fire-and-forget: the call does not wait for the verb to finish and yields
no value, so a Func<…, T> cannot be invoked — the compiler says so by name rather than handing you a value that
never arrives. Use Action for a callback and a plain function when you want a result.
Component-parameter wrappers#
Writable on a component parameter, where they mean something the plain type cannot say:
| You write | What it is |
|---|---|
Binding<T> | A two-way binding — the component reads and writes the caller's value. |
Query<T> | A reactive query handle the component re-reads as the data changes. |
Content | An opaque children slot — whatever the caller nests inside. |
Slot | A named children slot. See Slot (child content). |
component TypeDropdown(Binding<OrganizationType> value) { … }Types you declare#
Everything else is yours: an entity (persisted), an enum, a plain class (in-memory), and a component's own
type parameters. Those are named by their declaration and scoped by namespace and type visibility (public / internal).
Examples#
Scalars and a collection, together in one function, so the spellings on this page are shown compiling rather than only described. (Callables belong to a component or a class, so their example lives in Callables above.)
string Summarise(string title, List<decimal> amounts) {
decimal total = 0;
foreach (var a in amounts) {
if (a > 0) total = total + a;
}
return title + ": " + total;
}
// Summarise("Q1", [10, -5, 20]) -> "Q1: 30"See also#
- Types — the types with a wrinkle worth reading about first
- Optional and required members — which bare members are required, and when
?is needed - entity members — declaring these as entity members
- component — where
Binding<T>,Query<T>,ContentandSlotare used - Classes — plain in-memory value shapes