alepha@docs:~/docs/guides/core$
cat 6-types.md
3 min read
Last commit:

#Types

Alepha provides schema validation through the t singleton from "alepha". It wraps TypeBox with opinionated defaults: objects reject extra properties, strings have length limits, and arrays cap their size.

#Basic Usage

typescript
1import { t } from "alepha";2 3const userSchema = t.object({4  id: t.uuid(),5  email: t.email(),6  name: t.text(),7  age: t.optional(t.integer()),8});

t is a TypeProvider instance. All methods return TypeBox schemas that work with standard TypeBox utilities (Value.Check, Value.Decode, etc.).

#Strings

#t.string() vs t.text()

t.string() creates a raw string with no length limit. Use it for internal values where length is irrelevant.

t.text() adds length limits and text processing. Use it for user input, database fields, and API schemas.

typescript
1t.string()                  // no limits2t.text()                    // max 255 chars, trimmed3t.text({ size: "short" })   // max 64 chars, trimmed4t.text({ size: "long" })    // max 1024 chars, trimmed5t.text({ size: "rich" })    // max 65535 chars, trimmed

t.text() trims whitespace by default. You can control this and enable lowercase conversion:

typescript
1t.text({ trim: false })          // no trimming2t.text({ trim: true, lowercase: true })  // trim + lowercase

#Text Presets

Shorthand methods for common text sizes:

typescript
1t.shortText()   // same as t.text({ size: "short" })  — 64 chars2t.longText()    // same as t.text({ size: "long" })   — 1024 chars3t.richText()    // same as t.text({ size: "rich" })   — 65535 chars

#Default Length Limits

These static properties control the defaults. Override them at startup if needed:

typescript
1TypeProvider.DEFAULT_STRING_MAX_LENGTH       // 2552TypeProvider.DEFAULT_SHORT_STRING_MAX_LENGTH  // 643TypeProvider.DEFAULT_LONG_STRING_MAX_LENGTH   // 10244TypeProvider.DEFAULT_RICH_STRING_MAX_LENGTH   // 65535
typescript
1import { TypeProvider } from "alepha/core";2 3TypeProvider.DEFAULT_STRING_MAX_LENGTH = 512;4TypeProvider.DEFAULT_RICH_STRING_MAX_LENGTH = 100000;

#Numbers

typescript
1t.number()    // any number2t.integer()   // integer (no fractional part)3t.int32()     // integer clamped to signed 32-bit range (-2147483647 to 2147483647)4t.int64()     // JS-safe integer (-9007199254740991 to 9007199254740991)

t.int64() is NOT a true 64-bit integer. JavaScript cannot represent all int64 values. For true int64, use t.bigint() which stores values as strings.

All number methods accept TypeBox number options:

typescript
1t.integer({ minimum: 0, maximum: 100 })2t.number({ exclusiveMinimum: 0 })

#Objects

Objects reject additional properties by default:

typescript
1const schema = t.object({2  name: t.text(),3  email: t.email(),4});5// { name: "alice", email: "[email protected]", extra: true } → validation error

To allow additional properties:

typescript
1t.object({ name: t.text() }, { additionalProperties: true })

#Arrays

Arrays are limited to 1000 items by default:

typescript
1t.array(t.string())                      // max 1000 items2t.array(t.string(), { maxItems: 50 })    // max 50 items3t.array(t.string(), { minItems: 1 })     // at least 1 item

Override the global default:

typescript
1TypeProvider.DEFAULT_ARRAY_MAX_ITEMS = 5000;

#Modifiers

#Optional and Nullable

typescript
1t.optional(t.string())    // string | undefined2t.nullable(t.string())    // string | null

These can be combined:

typescript
1t.optional(t.nullable(t.string()))  // string | null | undefined

#Partial, Pick, Omit

typescript
1const user = t.object({2  id: t.uuid(),3  name: t.text(),4  email: t.email(),5});6 7t.partial(user)                  // all fields optional8t.pick(user, ["id", "name"])     // only id and name9t.omit(user, ["id"])             // name and email only

All three preserve the additionalProperties: false default.

#Extend

Add properties to an existing schema:

typescript
1const baseUser = t.object({2  id: t.uuid(),3  name: t.text(),4});5 6const admin = t.extend(baseUser, {7  role: t.const("admin"),8  permissions: t.array(t.text()),9});

t.extend also accepts an array of schemas to merge multiple bases:

typescript
1t.extend([baseUser, timestamped], { extra: t.text() })

#Nullify

Maps all properties of an object to nullable:

typescript
1const schema = t.object({2  name: t.text(),3  age: t.integer(),4});5 6t.nullify(schema)7// equivalent to: { name: string | null, age: number | null }

#Format Types

#Bigint

String-encoded arbitrary-precision integer:

typescript
1t.bigint()   // validates "123456789", "-42", etc.

Values are represented as strings to avoid JavaScript number limitations.

#UUID

typescript
1t.uuid()   // validates UUID format (e.g. "550e8400-e29b-41d4-a716-446655440000")

#URL

typescript
1t.url()   // validates URL format

#File and Stream

typescript
1t.file()                      // file-like object (browser File API compatible)2t.file({ maxSize: 1048576 })  // with size limit (bytes)3t.stream()                    // experimental streaming type

#Domain Types

#Email

typescript
1t.email()   // validates email format, auto-trims and lowercases

#Phone (E.164)

typescript
1t.e164()   // validates E.164 format, e.g. "+1234567890"

#Language Tag (BCP 47)

typescript
1t.bcp47()   // validates BCP 47 tags, e.g. "en", "en-US", "fr-CA"

#Date and Time

typescript
1t.datetime()   // ISO 8601 date-time, e.g. "2024-01-15T10:30:00Z"2t.date()       // ISO 8601 date, e.g. "2024-01-15"3t.time()       // ISO 8601 time, e.g. "10:30:00"4t.duration()   // ISO 8601 duration, e.g. "P1DT12H"

#Enums

String enums with built-in validation:

typescript
1t.enum(["ACTIVE", "INACTIVE", "BANNED"])2// validates that the value is one of the listed strings

Enum values are validated both by pattern matching and by an enum constraint on the schema.

#Other Types

typescript
 1t.const("value")    // literal value 2t.boolean()         // boolean 3t.null()            // null 4t.any()             // any (no validation) 5t.void()            // void 6t.undefined()       // undefined 7t.union([...])      // union of schemas 8t.tuple([...])      // fixed-length array 9t.record(k, v)      // Record<K, V>10t.json()            // Record<string, any> — convenience for JSON blobs

#Validation

Alepha validates data through alepha.codec.validate(). This is the same validation used internally by $action, $env, and other primitives.

typescript
 1import { Alepha, t } from "alepha"; 2  3const alepha = Alepha.create(); 4const schema = t.object({ 5  name: t.text(), 6  email: t.email(), 7}); 8  9const result = alepha.codec.validate(schema, {10  name: "  Alice  ",11  email: "[email protected]",12});13// result: { name: "Alice", email: "[email protected]" }

Validation does more than type checking. It applies preprocessing defined by t.text():

  • Trimming: strings created with t.text() are trimmed by default.
  • Lowercase: strings with lowercase: true (like t.email()) are lowercased.
  • Null coercion: null values in non-nullable fields become undefined, which are then stripped from objects.

If validation fails, a TypeBoxError is thrown with details about the first failing constraint.

#Validation Options

typescript
1alepha.codec.validate(schema, value, {2  trim: true,              // apply text trimming (default: true)3  nullToUndefined: true,   // convert null to undefined for non-nullable fields (default: true)4  deleteUndefined: true,   // remove undefined keys from objects (default: true)5});

#Encoding

alepha.codec.encode() validates data and serializes it to a target format:

typescript
 1const schema = t.object({ 2  id: t.uuid(), 3  name: t.text(), 4}); 5  6// Validate and return the cleaned object (default) 7const obj = alepha.codec.encode(schema, data); 8  9// Validate and serialize to JSON string10const json = alepha.codec.encode(schema, data, { as: "string" });11 12// Validate and serialize to binary (for protobuf, msgpack, etc.)13const bytes = alepha.codec.encode(schema, data, { as: "binary" });

You can skip validation with validation: false:

typescript
1alepha.codec.encode(schema, data, { validation: false, as: "string" });

#Codec Formats

The default codec is "json". Alepha also ships a "keyless" codec (smaller payloads, used for internal RPC). Additional codecs like Protobuf can be registered:

typescript
1alepha.codec.register({2  name: "protobuf",3  codec: myProtobufCodec,4});5 6alepha.codec.encode(schema, data, { encoder: "protobuf", as: "binary" });

#Decoding

alepha.codec.decode() deserializes data and validates it against a schema:

typescript
1const result = alepha.codec.decode(schema, jsonString);2// result is validated and typed as Static<typeof schema>

Specify a codec if the data isn't standard JSON:

typescript
1const result = alepha.codec.decode(schema, binaryData, { encoder: "protobuf" });

Validation runs automatically after decoding. Disable it with validation: false.

#Accessing TypeBox Directly

If you need raw TypeBox functionality:

typescript
1t.raw   // the TypeBox Type object
typescript
1t.raw.Intersect([schemaA, schemaB])