TypeScript Setup
How Zanith provides compile-time type safety without code generation — and why that matters.
Why this matters
A typo in a field name shouldn't be something you discover in production. It should be a red squiggle in your editor, caught before you even save the file. Most ORMs achieve this by generating thousands of lines of type definitions. Zanith does it with zero generation — using TypeScript's own inference system.
Without types
- ×Typos discovered at runtime
- ×Wrong types cause silent bugs
- ×No autocomplete on field names
- ×Refactoring breaks silently
With Zanith types
- ✓Typos caught at compile time
- ✓Wrong types are TS errors
- ✓Full autocomplete everywhere
- ✓Refactoring is safe
How it works — the inference chain
When you call m.string(), it returns a FieldBuilder<string>. When you chain .nullable(), it becomes FieldBuilder<string | null>. This phantom type flows through the entire chain — no files generated, no build step.
FieldBuilder<string>
extracts types
maps to API
ModelAPI<User>
// Each builder carries its TypeScript type:m.string() // → FieldBuilder<string>m.int() // → FieldBuilder<number>m.boolean() // → FieldBuilder<boolean>m.datetime() // → FieldBuilder<Date>m.bigint() // → FieldBuilder<bigint>m.string().nullable() // → FieldBuilder<string | null>m.json<MyType>() // → FieldBuilder<MyType> // defineModel extracts the full type map:const User = defineModel((m) => ({ fields: { email: m.string(), // string name: m.string().nullable(), // string | null age: m.int(), // number },})); // createZanith maps model names to typed APIs:const db = await createZanith({ models: { User }, adapter }); // Result is fully typed:const users = await db.user.findMany();// users: Array<{ email: string, name: string | null, age: number }>What TypeScript catches
With Zanith's type system, these common mistakes become impossible:
// ✅ Correct — email is string, age is numberdb.user.findMany({ where: { email: '[email protected]' } });db.user.findMany({ where: { age: { gt: 18 } } }); // ❌ TS Error — 'emale' is not a field on Userdb.user.findMany({ where: { emale: 'test' } }); // ❌ TS Error — age expects number filter, not stringdb.user.findMany({ where: { age: { gt: 'eighteen' } } }); // ❌ TS Error — 'status' doesn't exist on this modeldb.user.create({ data: { status: 'active' } });Recommended tsconfig.json
Zanith requires strict: truefor full type inference. Without strict mode, phantom types won't propagate correctly.
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }}Next steps
- Schema System — models, fields, relations, and the .zn DSL
- Query System — CRUD, relational queries, aggregates
- Type System Reference — all type exports and utilities