CURRENCY_AMOUNT()function
Create a CurrencyAmountSchema for a non-negative monetary amount in a currency.
CURRENCY_AMOUNT(currency: CurrencyCode): CurrencyAmountSchema
Schema validation for TypeScript. A Schema<T> describes how to coerce and validate an unknown value into a typed T. Schemas are the foundation of shelving — database collections, API endpoints, and form handlers all build on them.
By convention, instantiated schemas are constants and use UPPERCASE.
Schema<T> interfaceEvery schema has a single Schema.validate() method — validate(value: unknown): T. If the value is valid (after any coercion), it returns T. If it is not, it throws a plain string error message — for example "Must be 5–50 characters" or "Required". This is intentional: form handlers and API layers can consume these strings directly without any unwrapping.
Multi-field errors from DataSchema are joined by \n, one line per failed field, with the field name prepended: "name: Required\nemail: Invalid format".
validate() is called with undefined when no value is provided; the schema falls back to its Schema.value default.
Schema functionality in Shelving follows the robustness principle: "be conservative in what you do, be liberal in what you accept from others". Values that are obvious in their intent are coerced to appropriate valid values.
StringSchema converts numbers to strings, BooleanSchema converts the strings "no" and "false" to false and tests other values for truthiness, ArraySchema splits comma-separated strings into arrays, NumberSchema parses strings into numbers.
Every schema carries optional display metadata set at construction time:
| Property | Default | Purpose |
|---|---|---|
Schema.one | "value" | Singular noun, e.g. "product" |
Schema.many | one + "s" | Plural noun, e.g. "products" |
Schema.title | "" | Human-readable label for a field |
Schema.description | "" | Longer description for a field |
Schema.placeholder | "" | Placeholder text for an input |
Schema.value | schema-specific | Default used when validate(undefined) is called |
Schema.format() | schema-specific | Display formatter for downstream form and UI use |
For convenience the shelving/schema module offers sugar constants and factories to improve the readability of code that creates complex schemas. Sugar instances are pre-instantiated copies of Schema classes — by convention an instantiated schema is named in ALL_CAPS, a convention you will find it convenient to use in your own codebase too. Sugar factories are functions like OPTIONAL() and DATA() that build a configured schema for you.
| Sugar instance / factory | Validated type |
|---|---|
STRING | string |
NUMBER | number |
CURRENCY_AMOUNT(code) | number |
BOOLEAN | boolean |
DATA(props) | T (plain object) |
ARRAY(itemSchema) | readonly T[] |
CHOICE(options) | union of string keys |
NULLABLE(schema) | T | null |
OPTIONAL(schema) | T | undefined |
PARTIAL(schema) | Partial<T> |
ITEM(idSchema, props) | { id: I } & T |
Schemas compose: primitives, wrappers (NULLABLE(), OPTIONAL(), ARRAY()), and DATA() nest freely to describe an entire payload in a single validator. See each schema's own page for detailed usage of that class and its constants.
import { ITEM, STRING, REQUIRED_STRING, NUMBER, ARRAY, OPTIONAL, INTEGER } from "shelving/schema";
const PRODUCT = ITEM(INTEGER, {
name: REQUIRED_STRING,
price: NUMBER,
tags: ARRAY(STRING),
notes: OPTIONAL(STRING),
});
PRODUCT.validate({ id: 1, name: "Widget", price: 9.99, tags: "a,b" });
// { id: 1, name: "Widget", price: 9.99, tags: ["a", "b"], notes: undefined }
PRODUCT.validate({ id: 2, name: "", price: 9.99, tags: [] });
// throws "name: Required"Create a CurrencyAmountSchema for a non-negative monetary amount in a currency.
CURRENCY_AMOUNT(currency: CurrencyCode): CurrencyAmountSchema
Create a NullableSchema for an optional monetary amount in a currency, or null.
NULLABLE_CURRENCY_AMOUNT(currency: CurrencyCode): NullableSchema<number>
Create a DataSchema for a set of properties.
DATA(props: Schemas<T>): DataSchema<T>
Create a schema for a valid data object with specified properties, or null.
NULLABLE_DATA(props: Schemas<T>): NullableSchema<T>
Create a DataSchema that validates partially, i.e. every property can be its value or undefined.
PARTIAL(source: Schemas<T> | DataSchema<T>): DataSchema<PartialData<T>>
Create a DataSchema that validates a data item, i.e. it has a string or number .id identifier property.
ITEM(id: Schema<I>, schemas: Schemas<T> | DataSchema<T>): DataSchema<Item<I, T>>
Create a NullableSchema that wraps a source schema and also allows null.
NULLABLE(source: Schema<T>): NullableSchema<T>
Create a RequiredSchema that wraps a source schema and rejects a falsy result.
REQUIRED(source: Schema<T>): RequiredSchema<T>
Create an OptionalSchema that wraps a source schema and also allows undefined.
OPTIONAL(source: Schema<T>): OptionalSchema<T>
Create a schema for a valid dictionary object with specified entry values.
DICTIONARY(items: Schema<T>): DictionarySchema<T>
Create a schema for a valid array with specified items.
ARRAY(items: Schema<T>): ArraySchema<T>
Create a schema for a valid choice from an allowed set of values.
CHOICE(options: PossibleChoiceOptions<K>): ChoiceSchema<K>
Schema that defines a valid UTC datetime in ISO 8601 format, e.g. 2005-09-12T18:15:00.000Z.
new DateTimeSchema({ one = "time", title = "Time", input = "datetime-local", ...options }: DateSchemaOptions)Schema that defines a valid password string.
new PasswordSchema({ one = "password", title = "Password", min = 6, input = "password", ...options }: StringSchemaOptions = {})Schema that defines a valid slug, e.g. this-is-a-slug.
new SlugSchema({ max = 32, ...options }: SlugSchemaOptions)Schema that defines a valid string.
new StringSchema({
one = "string",
min = 0,
max = Number.POSITIVE_INFINITY,
value = "",
rows = 1,
match,
case: _case,
input = "text",
...options
}: StringSchemaOptions)Schema that defines a valid ISO 4217 currency code, e.g. GBP.
new CurrencyCodeSchema({ one = "currency", title = "Currency", currencies = CURRENCY_CODES, max = 3, ...options }: CurrencyCodeSchemaOptions)Schema that wraps and passes through to a source schema, used as a base for schemas that augment another schema's behaviour (e.g. NullableSchema, OptionalSchema, RequiredSchema).
new ThroughSchema<T>({ source, ...options }: ThroughSchemaOptions<T>)Schema that defines a valid email address.
new EmailSchema({ one = "email address", title = "Email", input = "email", max = 254, ...options }: EmailSchemaOptions)Schema that defines a valid ISO 3166 country code, e.g. GB.
new CountrySchema({ one = "country", title = "Country", value = "detect", ...options }: CountrySchemaOptions = {})Schema that defines a valid phone number.
new PhoneSchema({ one = "phone number", title = "Phone", input = "tel", max = 16, ...options }: PhoneSchemaOptions)Schema representing a numeric amount in a specific currency.
new CurrencyAmountSchema({ currency, one = "amount", title = "Amount", symbol, step, ...options }: CurrencyAmountSchemaOptions)Schema is an object instance with a validate() method that converts unknown input into a known, valid type T.
new Schema<T>({ one = "value", many = `${one}s`, title, description, placeholder, value }: SchemaOptions)Schema that defines a valid boolean.
new BooleanSchema({ value = false, required = false, ...options }: BooleanSchemaOptions)Schema that validates a data object against a fixed set of named property schemas.
new DataSchema<T>({ one = "item", title = "Item", props, value: partialValue, ...options }: DataSchemaOptions<T>)Schema that wraps a source schema and additionally allows null.
new NullableSchema<T>({ value = null, ...options }: NullableSchemaOptions<T>)Schema that defines a valid absolute URI string.
new URISchema({ one = "URI", title = "URI", schemes = HTTP_SCHEMES, input = "url", max = 512, ...options }: URISchemaOptions)Schema that validates a database key string, stripping any non-alphanumeric characters.
new KeySchema({ one = "key", title = "Key", min = 1, max = 32, ...options }: StringSchemaOptions)Schema that wraps a source schema but rejects a falsy result.
new RequiredSchema<T>()
Schema that wraps a source schema and additionally allows undefined.
new OptionalSchema<T>(options: OptionalSchemaOptions<T>)
Schema that validates a dictionary object whose entries all share the same value schema and have string keys.
new DictionarySchema<T>({
items,
one = items.one,
many = items.many,
placeholder = `No ${many}`,
min = 0,
max = Number.POSITIVE_INFINITY,
title = "Items",
value = {},
...options
}: DictionarySchemaOptions<T>)Schema that defines a valid number.
new NumberSchema({
one = "number",
title = "Number",
min = Number.NEGATIVE_INFINITY,
max = Number.POSITIVE_INFINITY,
step,
format = formatNumber,
value,
...options
}: NumberSchemaOptions)Schema that defines a valid date stored as a YYYY-MM-DD string, e.g. 2005-09-12.
new DateSchema({ one = "date", min, max, value, input = "date", step, ...options }: DateSchemaOptions)Schema that defines a valid color hex string, e.g. #00CCFF
new ColorSchema({ one = "color", title = "Color", value = "#000000", input = "color", max = 7, ...options }: ColorSchemaOptions)Schema that validates a file name matching one or more extensions.
new FileSchema({ one = "file", title = "File", types, ...options }: FileSchemaOptions)Schema that defines a valid UUID string (versions 1-5). Defaults to any-version validation.
new UUIDSchema({ one = "UUID", title = "UUID", max = 36, ...rest }: UUIDSchemaOptions = {})Schema that validates a postal address.
new AddressSchema({ one = "address", title = "Address", ...options }: AddressSchemaOptions = {})Schema that validates an array and ensures every item matches a specified item schema.
new ArraySchema<T>({
items,
one = items.one,
many = items.many,
title = "Items",
placeholder = `No ${many}`,
unique = false,
min = 0,
max = Number.POSITIVE_INFINITY,
separator = ",",
value = [],
...options
}: ArraySchemaOptions<T>)Schema that defines a valid absolute or relative URL string.
new URLSchema({ one = "URL", title = "URL", base, schemes = HTTP_SCHEMES, input = "url", max = 512, ...options }: URLSchemaOptions)Schema that validates an Entity string combining a type and ID, e.g. challenge:a1b2c3.
new EntitySchema<T>({ one = "entity", title = "Entity", types, ...options }: EntitySchemaOptions<T>)Schema that validates a value against a fixed set of allowed string choices.
new ChoiceSchema<O, I>({ one = "choice", title = "Choice", placeholder = `No ${one}`, options, value, ...rest }: ChoiceSchemaOptions<O, I>)Schema that defines a valid abstract time in 24h hh:mm:ss.fff format, e.g. 23:59 or 24:00.
new TimeSchema({ one = "time", title = "Time", input = "time", ...options }: DateSchemaOptions)Options for a SlugSchema.
{
readonly value?: string | undefined;
readonly max?: number | undefined;
readonly match?: RegExp | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
}Options for StringSchema.
{
readonly value?: string | undefined;
readonly min?: number | undefined;
readonly max?: number | undefined;
readonly rows?: number | undefined;
readonly match?: RegExp | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
}Options for CurrencyCodeSchema.
{
readonly value?: string | undefined;
readonly max?: number | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
readonly currencies?: ImmutableArray<CurrencyCode> | undefined;
}Allowed options for ThroughSchema.
{
source: Schema<T>;
}Options for an EmailSchema.
{
readonly value?: string | undefined;
readonly max?: number | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
}Options for CountrySchema.
{
readonly value?: PossibleCountry;
}Options for a PhoneSchema.
{
readonly value?: string | undefined;
readonly max?: number | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
}Options for CurrencyAmountSchema.
{
readonly symbol?: string | undefined;
readonly currency: CurrencyCode;
}Allowed options for BooleanSchema.
{
readonly value?: boolean | undefined;
readonly required?: boolean | undefined;
}Options for DataSchema.
{
readonly props: Schemas<T>;
readonly value?: Partial<T> | undefined;
}Allowed options for NullableSchema.
{
readonly value?: T | null;
}Options for URISchema.
{
readonly value?: string | undefined;
readonly max?: number | undefined;
readonly match?: RegExp | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
readonly schemes?: URISchemes | undefined;
}Allowed options for OptionalSchema.
{
readonly value?: undefined;
}Options for DictionarySchema.
{
readonly items: Schema<T>;
readonly value?: ImmutableDictionary | undefined;
readonly min?: number | undefined;
readonly max?: number | undefined;
}Allowed options for NumberSchema.
{
readonly value?: number | undefined;
readonly min?: number | undefined;
readonly max?: number | undefined;
readonly step?: number | undefined;
readonly format?: typeof formatNumber | undefined;
}Options for DateSchema.
{
readonly value?: PossibleDate | undefined;
readonly min?: Nullish<PossibleDate>;
readonly max?: Nullish<PossibleDate>;
readonly input?: DateInputType | undefined;
readonly step?: number | undefined;
}Options for a ColorSchema.
{
readonly value?: string | undefined;
readonly max?: number | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
}Allowed options for FileSchema.
{
readonly types?: FileTypes | undefined;
}Options for a UUIDSchema.
{
readonly value?: string | undefined;
readonly max?: number | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
}Allowed options for AddressSchema.
{
readonly value?: Partial<AddressData> | undefined;
}Options for ArraySchema.
{
readonly value?: ImmutableArray;
readonly items: Schema<T>;
readonly min?: number;
readonly max?: number;
readonly unique?: boolean;
readonly separator?: string | RegExp;
}Options for URLSchema.
{
readonly value?: string | undefined;
readonly max?: number | undefined;
readonly match?: RegExp | undefined;
readonly case?: "upper" | "lower" | undefined;
readonly input?: StringInputType | undefined;
readonly base?: URL | URLString | undefined;
readonly schemes?: URISchemes | undefined;
}Options for EntitySchema.
{
readonly types?: ImmutableArray<T> | undefined;
}Options for ChoiceSchema.
{
readonly options: PossibleChoiceOptions<O>;
readonly value?: O | I;
}type="" prop for HTML <input /> tags that are relevant for strings.
"text" | "password" | "color" | "email" | "number" | "tel" | "search" | "url"
Options allowed by a Schema instance.
{
readonly one?: string;
readonly many?: string;
readonly title?: string | undefined;
readonly description?: string | undefined;
readonly placeholder?: string | undefined;
readonly value?: unknown;
}Extract the validated value type T from a Schema<T>.
X extends Schema<infer Y> ? Y : never
A set of named schemas in { name: schema } format.
{ readonly [K in keyof T]: Schema<T[K]> }type="" prop for HTML <input /> tags that are relevant for dates.
"time" | "date" | "datetime-local"
Dictionary of allowed options for a ChoiceSchema in { key: title } format.
{ readonly [KK in K]: string }Things that can be converted to a ChoiceOptions dictionary.
ImmutableArray<K> | ChoiceOptions<K>
Sugar instance of DateTimeSchema for a required UTC datetime. Equivalent to new DateTimeSchema({}).
Sugar instance allowing a DATETIME or null. Equivalent to NULLABLE(DATETIME).
Sugar instance of PasswordSchema for a password string. Equivalent to new PasswordSchema({}).
Sugar instance of SlugSchema for a valid slug. Equivalent to new SlugSchema({}).
Sugar instance allowing a SLUG or null. Equivalent to NULLABLE(SLUG).
Sugar instance of StringSchema for an unconstrained string. Equivalent to new StringSchema({}).
Sugar instance of StringSchema requiring at least one character. Equivalent to new StringSchema({ min: 1 }).
Sugar instance of StringSchema for a title of 1–100 characters. Equivalent to new StringSchema({ one: "title", title: "Title", min: 1, max: 100 }).
Sugar instance allowing a TITLE or null. Equivalent to NULLABLE(TITLE).
Sugar instance of StringSchema for a name of 1–100 characters. Equivalent to new StringSchema({ one: "name", title: "Name", min: 1, max: 100 }).
Sugar instance allowing a NAME or null. Equivalent to NULLABLE(NAME).
Sugar instance of CurrencyCodeSchema for a required ISO 4217 currency code, e.g. GBP. Equivalent to new CurrencyCodeSchema({}).
Sugar instance allowing a CURRENCY_CODE or null. Equivalent to NULLABLE(CURRENCY_CODE).
Sugar instance of EmailSchema for a valid email address. Equivalent to new EmailSchema({}).
Sugar instance allowing an EMAIL or null. Equivalent to NULLABLE(EMAIL).
Sugar instance of CountrySchema for a required ISO 3166 country code, e.g. GB. Equivalent to new CountrySchema({}).
Sugar instance allowing a COUNTRY or null. Equivalent to NULLABLE(COUNTRY).
Sugar instance of PhoneSchema for a valid phone number. Equivalent to new PhoneSchema({}).
Sugar instance allowing a PHONE or null. Equivalent to NULLABLE(PHONE).
Sugar instance of CurrencyAmountSchema for a US dollar amount. Equivalent to new CurrencyAmountSchema({ currency: "USD" }).
Sugar instance of CurrencyAmountSchema for a pound sterling amount. Equivalent to new CurrencyAmountSchema({ currency: "GBP" }).
Sugar instance of CurrencyAmountSchema for a euro amount. Equivalent to new CurrencyAmountSchema({ currency: "EUR" }).
Sugar instance allowing a USD_AMOUNT or null. Equivalent to NULLABLE(USD_AMOUNT).
Sugar instance allowing a GBP_AMOUNT or null. Equivalent to NULLABLE(GBP_AMOUNT).
Sugar instance allowing an EUR_AMOUNT or null. Equivalent to NULLABLE(EUR_AMOUNT).
Unknown validator that always passes through its input value as unknown.
UNKNOWN: Schema<unknown>
Undefined validator that always returns undefined.
UNDEFINED: Schema<undefined>
Null validator that always returns null.
NULL: Schema<null>
Sugar instance of BooleanSchema for a coerced boolean. Equivalent to new BooleanSchema({}).
Sugar instance of URISchema for an absolute URI string. Equivalent to new URISchema({}).
Sugar instance allowing a URI_SCHEMA or null. Equivalent to NULLABLE(URI_SCHEMA).
Sugar instance of KeySchema for a database key. Equivalent to new KeySchema({ title: "ID" }).
Sugar instance allowing a KEY or null. Equivalent to NULLABLE(KEY).
Sugar instance of NumberSchema for an unconstrained number. Equivalent to new NumberSchema({ title: "Number" }).
Sugar instance allowing a NUMBER or null. Equivalent to NULLABLE(NUMBER).
Sugar instance of NumberSchema for an integer. Equivalent to new NumberSchema({ step: 1, min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER }).
Sugar instance of NumberSchema for a positive integer (excluding zero). Equivalent to new NumberSchema({ step: 1, min: 1, max: Number.MAX_SAFE_INTEGER }).
Sugar instance of NumberSchema for a non-negative integer (including zero). Equivalent to new NumberSchema({ step: 1, min: 0, max: Number.MAX_SAFE_INTEGER }).
Sugar instance of NumberSchema for a negative integer (excluding zero). Equivalent to new NumberSchema({ step: 1, min: Number.MIN_SAFE_INTEGER, max: -1 }).
Sugar instance of NumberSchema for a non-positive integer (including zero). Equivalent to new NumberSchema({ step: 1, min: Number.MIN_SAFE_INTEGER, max: 0 }).
Sugar instance allowing an INTEGER or null. Equivalent to NULLABLE(INTEGER).
Sugar instance of NumberSchema for a Unix timestamp (including milliseconds). Equivalent to new NumberSchema({ title: "Timestamp", step: 1, min: Number.MIN_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER }).
Sugar instance — alias of NULLABLE_INTEGER. Equivalent to NULLABLE_INTEGER.
Sugar instance of DateSchema for a required date. Equivalent to new DateSchema({}).
Sugar instance allowing a DATE or null. Equivalent to NULLABLE(DATE).
Sugar instance of ColorSchema for a required hex color string, e.g. #00CCFF. Equivalent to new ColorSchema({}).
Sugar instance allowing a COLOR or null. Equivalent to NULLABLE(COLOR).
Sugar instance of FileSchema for a file name, e.g. file.txt. Equivalent to new FileSchema({}).
Sugar instance allowing a FILE or null. Equivalent to NULLABLE(FILE).
Sugar instance of UUIDSchema for any valid UUID (versions 1-5). Equivalent to new UUIDSchema({ title: "ID" }).
Sugar instance allowing a UUID or null. Equivalent to NULLABLE(UUID).
Sugar instance of AddressSchema for postal address data. Equivalent to new AddressSchema({}).
Sugar instance allowing an ADDRESS or null. Equivalent to NULLABLE(ADDRESS).
Sugar instance of URLSchema for an absolute or relative URL string. Equivalent to new URLSchema({}).
Sugar instance allowing a URL_SCHEMA or null. Equivalent to NULLABLE(URL_SCHEMA).
Sugar instance of EntitySchema for an entity string, e.g. challenge:a1b2c3. Equivalent to new EntitySchema({}).
Sugar instance allowing an ENTITY or null. Equivalent to NULLABLE(ENTITY).
Sugar instance of TimeSchema for a required abstract time. Equivalent to new TimeSchema({}).
Sugar instance allowing a TIME or null. Equivalent to NULLABLE(TIME).