TypeBox

repository·main·Indexed 11 days ago

https://github.com/sinclairzx81/typebox

A JSON Schema Type Builder that provides static type resolution for TypeScript. It allows developers to define runtime JSON Schema objects that automatically infer corresponding TypeScript types, enabling unified validation across both runtime and compile-time. Features include a high-performance JIT compiler via `Schema.Compile()`, a micro TypeScript engine via `Type.Script`, and support for Standard Schema V1 interfaces.

Tokens
74K
Snippets
332
Records
359
Agent score
90%

What's inside TypeBox

  1. What is TypeBox?

    main

    TypeBox is a JSON Schema Type Builder that provides static type resolution for TypeScript. It allows you to construct JSON Schema compliant schematics using a set of built-in types. These schematics can be used directly with any JSON Schema compliant validator. The library provides two categories of types:

    1. JSON Schema types: Used to construct standard JSON Schema fragments.
    2. Extended types: Used to model constructs native to the JavaScript language.

    TypeBox types are composable, meaning small schema fragments can be combined into more complex, nested structures.

  2. Use the Value submodule for typed operations

    main

    The Value submodule provides a suite of functions to process dynamic JavaScript values against a schema. Key capabilities include:

    • Validation and Parsing: Check and Parse for verifying and transforming values.
    • Data Transformation: Clone, Encode, and Decode for handling data lifecycle.
    • Structural Operations: Diff and Patch for performing advanced structural comparisons and updates on dynamic values.
  3. Use the TypeBox System module for core configurations

    main

    The typebox/system module provides access to core logic and global configurations. Use it to manage the following capabilities:

    • Language Configuration: Set and manage the current language via Locale.
    • Immutability: Enforce immutable schematics.
    • Debugging: Debug types and type-related logic.
    • Memory Management: Interact with the TypeBox memory management system via Memory.
    • Settings: Access global settings via Settings.
    import { Settings, Locale, Memory } from 'typebox/system'
  4. Use `Type.Dependent` for conditional JSON Schema logic

    main

    The Type.Dependent construct (and the if ... then ... else script syntax) implements JSON Schema if/then/else conditionals. Unlike TypeScript's Conditional types which evaluate immediately based on static types, Dependent types defer evaluation to runtime, allowing the schema to refine values based on the actual data present (e.g., a status field determining the shape of the rest of an object).

    // Using the Type API
    const T = Type.Dependent(Type.Number(), Type.Literal(1), Type.String())
    
    // Using the Script API
    const T = Type.Script('if number then 1 else string')
    
    // Complex example: API response shape depending on status
    const Response = Type.Script(`{
      status: 'success' | 'error'
    } & (
      if { status: 'success' } then {
        data: unknown
      } else {
        message: string
        code: number
      }
    })`)
  5. Simplify Intersections using Type.Evaluate

    main

    When evaluating a Type.Intersect, the function yields the narrowest constituent. For example, if an intersection contains a specific literal and a general type, Type.Evaluate will simplify the expression to the specific literal.

    const T = Type.Intersect([Type.Literal(1), Type.Number()])
    const S = Type.Evaluate(T) // const S = { const: 1 }
  6. Behavioral change in Value.Parse and Validator.Parse

    main

    In TypeBox 1.1.0 and later, the default behavior of Value.Parse and Validator.Parse has changed from automatic correction to strict validation.

    Comparison:

    Version 1.0 (Default):

    const A = Value.Parse(Type.Number(), '123') // Returns 123

    Version 1.1+ (Default):

    const A = Value.Parse(Type.Number(), '123') // Throws error: Expected Number
    // 1.1 behavior
    const A = Value.Parse(Type.Number(), '123') // throw! - Expected Number
  7. Use the Schema submodule for advanced JSON Schema layouts

    main

    The Schema submodule allows you to define custom JSON Schema layouts, such as using the $defs keyword for reusable definitions and $ref for cross-dependent types. This is useful for complex, modular schemas that go beyond the standard Type.* compositors.

    Note: Leveraging native JSON Schema inference may require familiarity with type-level programming, as TypeBox cannot provide a simplified interface for every possible custom layout.

  8. How Type.Module handles inlining, cyclic types, and dead code elimination

    main

    The Type.Module function is an advanced compositing system for referential types that performs several automatic normalization passes:

    1. Reference Inlining: When a type is referenced via Type.Ref, Type.Module automatically clones the referenced type directly into the referring type. This results in a self-contained type structure without external dependencies.
    2. Cyclic Type Resolution: If the module detects self-referential or mutually recursive types, it automatically transforms them into instances of TCyclic. This allows for complex, circular data structures.
    3. Dead Code Elimination: Type.Module ensures that each definition only includes the types required for its own structure. If a definition in the module is not referenced by any other part of the module, it is excluded from the resulting referential set of the exported types.
  9. Understand the CodeResult structure

    main

    The Code function returns a CodeResult object containing two properties: Code and External.

    • Code: A string containing the source code for the ESM module. This module typically exports two functions:
      • export function SetExternal(external): Used to configure external dependencies or variables.
      • export function Check(value): The primary validation function used to check a value against the schema.
    • External: An object containing metadata required to initialize the module, specifically the identifier and any variables needed by the generated code.
    import { Code } from 'typebox/compile'
    import { Type } from '@sinclair/typebox'
    
    const result = Code(Type.String())
    
    console.log(result.Code)     // Returns the ESM source code string
    console.log(result.External) // Returns { identifier: '...', variables: [...] }
  10. Simplify Unions using Type.Evaluate

    main

    When evaluating a Type.Union, the function yields the broadest variant within the set. For example, if a union contains a specific literal and a general type, Type.Evaluate will simplify the expression to the general type.

    const T = Type.Union([Type.Literal(1), Type.Number()])
    const S = Type.Evaluate(T) // const S = { type: 'number' }