Type System

Built-in types, custom definitions, arrays, and type constraints

Use types to describe the values your program accepts. Start with built-in types, then define custom shapes and add structural or semantic constraints. For variable annotation syntax, see Type Annotations.

Built-in Types

// Primitives
string    // Text
number    // Numeric values
boolean   // true/false
any       // Any value (no constraints)

// Collections
array     // Generic array
json      // Any valid JSON

// Special
file      // A file object: {path, filename, mimeType, size, url?}
Error     // Error objects (e.g. from tuple destructuring)

Notes:

  • null is a value, not a type — it cannot appear in annotations or unions. Use T?, which accepts the value, undefined, and null.
  • There is no files type — use file[].
  • A file is an object, not a path string; file values come from stdlib calls like generateImage().
  • Bare object accepts any object and keeps all its properties (passthrough). Prefer a literal shape ({name: string}) when you know the structure — it actually validates.

Custom Type Definitions

// Basic type
type Email = string + { email: true }

// With constraints
type Username = string + { min: 3, max: 20 }
type Temp = number + { int: true, min: 0, max: 60 }
// Negative bounds work too: number + { min: -50, max: -1 }

// Object type
type User = {
  name: string + { min: 1 },
  email: string + { email: true },
  age: number + { int: true, min: 0 }
}

// Array type
type Names = string[]

// Array length constraints (see "Array constraints" below)
type Scores = number[] + { minLength: 1, maxLength: 10 }

// Nested objects
type Person = {
  name: string,
  address: {
    street: string,
    city: string
  }
}

// Union types
type StringOrNumber = string | number

// Literal types (enums)
type Status = "active" | "pending" | "inactive"

// Optional — T? accepts the value, undefined, and null.
// (`number | null` is a parse error: null is not a type.)
type MaybeString = string?

Array Type Syntax

TypeScript-style array notation:

// Variable declarations
let names: string[] = ["Alice", "Bob"]
let scores: number[] = [95, 87, 92]

// Custom types
type User = {name: string}
let users: User[] = [{name: "Alice"}]

// Nested arrays
let matrix: number[][] = [[1, 2], [3, 4]]

// Function parameters and returns
function processNames(names: string[]): number {
  return names.length
}

Type Constraints

String constraints:

+ { min: n }         // Minimum length
+ { max: n }         // Maximum length
+ { length: n }      // Exact length
+ { email: true }    // Valid email format
+ { url: true }      // Valid URL format
+ { uuid: true }     // Valid UUID format
+ { regex: pattern } // Match regex pattern

Number constraints:

+ { min: n }         // Minimum value
+ { max: n }         // Maximum value
+ { int: true }      // Must be integer
+ { multipleOf: n }  // Must be multiple of n
+ { finite: true }   // Must be finite

Array constraints:

+ { minLength: n }   // Minimum array length
+ { maxLength: n }   // Maximum array length
+ { length: n }      // Exact array length

On array types the bounds are element counts: minLength/maxLength (with min/max accepted as aliases). Any other constraint key on an array type is a parse error — apply value constraints to the element type instead: (string + { email: true })[].

Example with constraints:

type ValidEmail = string + {
  min: 5,
  max: 255,
  email: true
}

type Percentage = number + {
  min: 0,
  max: 100,
  int: true
}

type ValidScores = number[] + {
  minLength: 1,
  maxLength: 10
}

Semantic Type Constraints

Use + { is: "..." } for human-readable semantic validation:

// String semantics
type PositiveMessage = string + {
  is: "a message expressing positive sentiment"
}

type ProductDesc = string + {
  min: 50,
  max: 500,
  is: "a compelling product description"
}

// Number semantics
type SatisfactionRating = number + {
  min: 1,
  max: 5,
  is: "a rating indicating satisfaction"
}

// Object semantics
type ServerConfig = {
  host: string,
  port: number
} + { is: "a valid server configuration" }

// Array semantics
type TodoList = string[] + {
  min: 1,
  is: "a list of high-priority tasks"
}

How semantic constraints work:

  • Provides human-readable validation criteria
  • Used by LLMs during generation
  • Runtime validation against semantic meaning
  • Combines with structural constraints

Next Steps