Advanced Topics

Type Safety & Inference

Type Safety & Inference in Tauri SQLite ORM.

Type Safety & Inference

One of the most powerful features of this ORM is its deep integration with TypeScript. The schema you define in schema.ts is not just a blueprint for your database; it's a single source of truth that the ORM uses to generate precise TypeScript types for all your data.

This means you get robust autocompletion, compile-time error checking, and less boilerplate code, as you rarely need to write your own interface or type definitions for your database models.

InferSelectModel

This is the most common helper type. It infers the type of a record as it would be selected from the database. This is the type you'll use when you're working with data fetched from a query.

import { InferSelectModel } from '@type32/tauri-sqlite-orm';
import { users } from '$lib/db/schema';

// This creates a `User` type directly from the schema.
export type User = InferSelectModel<typeof users>;

/*
If the `users` schema is:
{
  id: integer('id').primaryKey(),
  fullName: text('full_name').notNull(),
  createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
  bio: text('bio') // nullable
}

The inferred `User` type will be:
{
  id: number;
  fullName: string;
  createdAt: Date; // Correctly inferred from the 'timestamp' mode
  bio: string | null | undefined; // Correctly inferred as optional
}
*/

function displayUser(user: User) {
  console.log(user.fullName);
}

InferInsertModel

This helper type infers the shape of an object that can be passed to the .values() method of an insert query. It's different from InferSelectModel in one key way: it makes any column that is nullable, has a default value, or is auto-incrementing optional.

This is crucial because you don't need to provide these values when creating a new record.

import { InferInsertModel } from '@type32/tauri-sqlite-orm';
import { users } from '$lib/db/schema';

export type NewUser = InferInsertModel<typeof users>;

/*
Using the same schema as above, the `NewUser` type will be:
{
  id?: number; // Optional, because it's an auto-incrementing PK
  fullName: string; // Required, because it's NOT NULL and has no default
  createdAt?: Date; // Optional, because it likely has a .$defaultFn
  bio?: string | null | undefined; // Optional, because it's nullable
}
*/

// This is a valid object of type NewUser.
const userToInsert: NewUser = {
  fullName: 'John Doe',
};

await db.insert(users).values(userToInsert).execute();

InferRelationalSelectModel

Use this helper to infer the result type of a select query that includes relations via .include(with). This lets you type variables that hold results from relational queries without manually defining intersection types.

import { InferSelectModel, InferRelationalSelectModel } from '@type32/tauri-sqlite-orm';
import { schema } from '$lib/db/schema';

export type User = InferSelectModel<typeof schema.user>;

const withRelationalObject = { sessions: true, accounts: true } as const;
export type UserWithRelations = InferRelationalSelectModel<
  typeof schema.user,
  typeof schema.userRelations,
  typeof withRelationalObject
>;

// UserWithRelations = User & { sessions: Session[]; accounts: Account[] }

For nested includes, pass a map of table name → relations as the fourth parameter:

const withNested = { sessions: { with: { user: true } } } as const;
type UserWithSessionsAndUser = InferRelationalSelectModel<
  typeof schema.user,
  typeof schema.userRelations,
  typeof withNested,
  { user: typeof schema.userRelations; session: typeof schema.sessionRelations }
>;

By leveraging these inferred types, your IDE becomes a powerful partner, guiding you to write correct, type-safe database code and catching potential bugs before you even run your application.

Copyright © 2026