Skip to content

InferTable

InferTable<typeof table> gives you the TypeScript type of a row. It is computed from the column builders, so it is always in sync with your schema.

import { defineTable, int, text, InferTable } from "@mountsqli/core";
const users = defineTable("users", {
id: int().pk(),
email: text().notNull(),
age: int(), // nullable
});
type User = InferTable<typeof users>;
// ^? { id: number; email: string; age: number | null }

Other ORMs make you run a generator (prisma generate) to get row types. MountSQLI infers them directly from the column builders — there is nothing to run. Change a column, and every query result type updates on the next tsc.

const t = defineTable("t", {
a: int(), // number | null
b: int().notNull(), // number
});
type Row = InferTable<typeof t>;
// ^? { a: number | null; b: number }

When you use defineConfig, derive the app Db from the config instead of typing tables one by one:

import { mountsqli, type DbFromConfig } from "@mountsqli/core";
import config from "../mountsqli.config";
export const db = mountsqli(config);
export type AppDb = DbFromConfig<typeof config>;

mountsqli is generic and returns the typed Db. mountsqliExtended adds auth/realtime/storage subsystems structurally. Prefer mountsqliExtended when you use those.

The builder uses InferTable so .findOne() knows its return type:

const row = await db.from(users).findOne();
// ^? User | null
  • Export type User = InferTable<typeof users> next to each table.
  • Use DbFromConfig<typeof config> for the app-wide Db type.
  • Let the compiler catch column renames — don’t alias away the type.
  • Hand-writing a row interface that drifts from the table.
  • Using any for query results instead of the inferred type.