All types support nullable variants using optional syntax. Nullable columns can store NULL values.
Nullable columns require a separate null bitmap that ClickHouse checks on every row access. This overhead applies even if only one row contains NULL. For frequently-queried columns, prefer using default values (e.g., 0, "", or a sentinel value) instead of Nullable.
interface User { name: string; // Required - NOT NULL email?: string; // Nullable(String) age?: number; // Nullable(Float64) verified?: boolean; // Nullable(Boolean)}If a field is optional but you provide a ClickHouse default, Moose creates a non-nullable column with a DEFAULT clause instead of a Nullable column.
import { ClickHouseDefault, WithDefault } from "@514labs/moose-lib"; interface User { name: string; // Optional without default → Nullable(Int64) age?: number; // Optional with default → Int64 DEFAULT 18 (non-nullable) minAge?: number & ClickHouseDefault<"18">; // Alternative helper syntax status?: WithDefault<string, "'active'">;}| Pattern | TypeScript | Python | ClickHouse Result |
|---|---|---|---|
| Required | field: T | field: T | T NOT NULL |
| Optional | field?: T | Optional[T] = None | Nullable(T) |
| Optional + Default | field?: T & ClickHouseDefault<"val"> | Annotated[Optional[T], clickhouse_default("val")] | T DEFAULT val |
ClickHouse defaults are SQL expressions. String defaults must include quotes: "'active'" not "active". Numeric defaults are bare: "18" not "'18'".