The Type System Architecture: Inside @objectql/types
A comprehensive deep dive into ObjectQL's type system - the constitutional layer that defines contracts, prevents circular dependencies, and enables universal compatibility.
The Type System Architecture: Inside @objectql/types
In any well-architected software system, there exists a foundational layer that defines the rules of engagement—the contract that all other components must honor. In ObjectQL, this is @objectql/types, often referred to as "The Constitution."
The Zero-Dependency Principle
One of the most critical architectural decisions in ObjectQL is the zero-dependency rule for @objectql/types. This package:
- Contains only Pure TypeScript interfaces, enums, and custom errors
- Has zero external dependencies
- Can never import from other ObjectQL packages
- Serves as the single source of truth for the entire ecosystem
Why Zero Dependencies Matter
This strict rule prevents circular dependencies and ensures a clean dependency graph:
The Core Type Hierarchy
1. Schema Types: The Data Model Contract
ObjectQL's schema types define how data structures are declared:
These interfaces are deliberately simple—they're designed to be serializable and validatable by both humans and AI agents.
2. Query Types: The AST Protocol
ObjectQL doesn't use SQL strings or MongoDB query objects directly. Instead, it defines an Abstract Syntax Tree (AST) for queries:
This AST approach provides several benefits:
- Type-Safe: TypeScript validates queries at compile time
- Serializable: Can be sent over HTTP as JSON
- Database-Agnostic: Drivers translate to their native formats
- AI-Friendly: LLMs can generate valid queries without knowing SQL syntax
3. Driver Interface: The Portability Contract
The Driver interface defines the contract that all database adapters must implement:
This interface is intentionally minimal. Advanced features (aggregations, transactions) are provided through optional capabilities that drivers can implement.
Custom Error Types: Type-Safe Error Handling
ObjectQL defines a hierarchy of custom errors instead of throwing generic Error objects:
This enables type-safe error handling:
Universal Runtime Compatibility
Because @objectql/types has zero dependencies and uses only pure TypeScript, it works in any JavaScript environment:
- ✅ Node.js
- ✅ Browser (via bundlers)
- ✅ Deno
- ✅ Cloudflare Workers
- ✅ Vercel Edge Functions
- ✅ React Native
This is crucial for ObjectQL's vision of "write once, run anywhere."
Versioning and Compatibility
The @objectql/types package follows strict semantic versioning:
- Major version: Breaking changes to interfaces (rare)
- Minor version: New interfaces or optional properties (common)
- Patch version: Documentation or internal improvements (frequent)
Since all packages depend on @objectql/types, version compatibility is critical:
The ^ (caret) ensures that updates to @objectql/types minor versions don't break dependent packages.
Best Practices for Using Types
1. Always Import from @objectql/types
2. Use Type Guards for Runtime Checks
3. Extend Types with Generics
The Constitutional Role
@objectql/types is more than just a package—it's the constitutional document of the ObjectQL ecosystem:
- Immutable Contracts: Interfaces define what's possible
- Universal Language: All packages speak the same types
- Stability Guarantees: Breaking changes require major versions
- AI-Readable: LLMs can understand and generate valid code
When you work with ObjectQL, you're not just using an ORM—you're operating within a type system that guarantees consistency, safety, and portability across the entire stack.
Learn More
Next in Series: Compiler vs ORM: Understanding ObjectQL's Execution Model