zanith

Type System

How Zanith provides compile-time type safety from schema definition to query results — without generating any code. This page covers every type export and utility.

The inference chain

Types flow automatically through the entire pipeline. Each step preserves and refines the type information from the previous step.

FieldBuilder<T>

carries scalar type

defineModel()

extracts type map

createZanith()

maps to ModelAPI<T>

findMany()

returns T[]

Scalar type mapping

Each builder method carries its TypeScript type as a phantom generic parameter:

Builder methodTypeScript typeWith .nullable()
m.string() / m.text() / m.uuid()stringstring | null
m.int() / m.float() / m.decimal()numbernumber | null
m.boolean()booleanboolean | null
m.datetime()DateDate | null
m.bigint()bigintbigint | null
m.json()unknownunknown | null
m.json()TT | null
m.bytes()BufferBuffer | null
m.enum(E)stringstring | null

Type exports

Import these types from 'zanith' for advanced type-level operations:

TS
import type {
// Model & field inference
InferModelFields, // Extract field type map from a TypedModelDefinition
InferFieldTypes, // Extract type map from a Record<string, FieldBuilder>
InferFieldType, // Extract T from a single FieldBuilder<T>
TypedModelDefinition, // Model definition with phantom field types
 
// Query input types
TypedWhereInput, // Where clause constrained to model field names & types
FilterOpsFor, // Map a scalar type to its filter operators
 
// Client types
TypedZanithClient, // Fully typed client (model names → ModelAPI instances)
 
// Utility types
Nullify, // Make all fields T | null (for LEFT JOIN propagation)
} from 'zanith';

InferModelFields

Extracts the field type map from a model definition. Use this when you need to reference a model's types in your own code.

TS
const User = defineModel((m) => ({
name: 'User', table: 'users',
fields: {
email: m.string(),
name: m.string().nullable(),
age: m.int(),
},
}));
 
type UserFields = InferModelFields<typeof User>;
// UserFields = { email: string, name: string | null, age: number }

TypedWhereInput

A mapped type that constrains the whereclause to valid field names and appropriate filter operators for each field's type.

TS
type UserWhere = TypedWhereInput<UserFields>;
 
// Valid:
const where1: UserWhere = { email: '[email protected]' };
const where2: UserWhere = { age: { gt: 18, lt: 65 } };
const where3: UserWhere = { OR: [{ role: 'ADMIN' }, { role: 'USER' }] };
 
// TypeScript errors:
const bad1: UserWhere = { emale: 'test' }; // ❌ unknown field
const bad2: UserWhere = { age: { gt: 'old' } }; // ❌ string, not number

FilterOpsFor

Maps a scalar TypeScript type to its available filter operators:

Scalar typeFilter typeAvailable operators
stringStringFilterOpsequals, not, in, notIn, contains, startsWith, endsWith, lt, gt
numberNumberFilterOpsequals, not, in, notIn, lt, lte, gt, gte
booleanBooleanFilterOpsequals, not
DateDateFilterOpsequals, not, lt, lte, gt, gte

Nullify

Wraps every field in T | null. Used internally for LEFT JOIN nullable propagation — fields from LEFT JOINed models may be null even if the field itself isn't nullable.

TS
type UserFields = { email: string, name: string | null, age: number };
type NullableUser = Nullify<UserFields>;
// NullableUser = { email: string | null, name: string | null, age: number | null }

TypedZanithClient

The fully typed client type. Maps model names to ModelAPI<T> instances with correct field types.

TS
type Models = { User: typeof User, Post: typeof Post };
type Client = TypedZanithClient<Models>;
 
// Client.user → ModelAPI<{ email: string, name: string | null, ... }>
// Client.post → ModelAPI<{ title: string, content: string | null, ... }>