Skip to main content

TypeScript Patterns

Voltaire uses specific TypeScript patterns for type safety, tree-shaking, and API consistency.

Branded Types

All primitives are branded Uint8Arrays - zero runtime overhead, full type safety.

Why Branded Types?

  1. Type Safety: Can’t accidentally pass Hash where Address expected
  2. Zero Overhead: Just TypeScript - no runtime checks
  3. Uint8Array Base: Works with all binary APIs natively
  4. Self-Documenting: Types describe exact byte lengths

File Organization

Each primitive follows this structure:

Why .js for Implementation?

Implementation files use .js with JSDoc types:
Benefits:
  • No compilation step for runtime code
  • JSDoc provides type checking
  • Better tree-shaking
  • Faster builds

Namespace Pattern

Functions are exported both internally and wrapped:

Usage

Why Dual Exports?

Constructor Pattern

Main Constructor

The primary constructor is just the type name:

Named Constructors

For specific input types:

Type Narrowing

Input Types

Define input types for flexible function signatures:

The from Function

Central converter that handles all inputs:

Validation Pattern

Type Guards

Validation Functions

Error Handling

Custom Errors

Usage in Functions

Testing Pattern

Tests in separate .test.ts files using Vitest:

Index File Template

Complete index.ts structure:

Common Mistakes

Avoid these patterns: