Types & Money
Storage is dynamically typed. The language layer is not. Declared shapes drive the typechecker, LSP, and executor drift handling.
Scalars
Id, Text, Int, Float, Bool, Money, Time, Duration, Bytes, Json, plus enum { … }, ref Other, and unknown.
Money (never float)
A money value is integer minor units + ISO 4217 currency — never a bare decimal float.
eel
49.99$usd // canonical
49.99$ // bare form — only where schema currency is known (e.g. Money<usd>)
500$jpy- Cross-currency arithmetic and comparison are type errors. Convert explicitly.
- In TypeScript,
@eelden/clientexposes an immutableMoneyclass overbigintminors — accidental+with a number is structurally hard.
Enums
eel
status: enum { trial, paid, suspended }
users |> filter status == .paidThe lexer is context-free: . is always a token. The parser reads .ident as an enum literal in primary position and as field access in postfix position.
unknown, is, and as
Drifted or Json-derived values surface as unknown. They are never silently coerced.
eel
events |> filter metadata.amount is Money
events |> select { cents: metadata.amount as Money<usd> }| Form | Meaning |
|---|---|
expr is Type | Bool predicate — runtime tag test |
expr as Type | Cast — fails per @strict / @loose |
Rejected assertions: is ref X, is enum { … }, is unknown.
Time and duration
eel
orders |> filter placed_at > now() - 7dnow() is wall time from the injected clock (injectable in tests and wasm). Duration literals like 7d participate in arithmetic with Time.