Type-Safe Query Construction
Build queries that reject invalid columns at compile time.
Type-Safe Query Construction is a free TypeScript Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Queries That Cannot Reference Unknown Columns
A type-safe query builder rejects column names that do not exist on the table at compile time. You reference columns through typed objects, not raw strings.
Typed Column References
After defining a table, each column is a property on the table object. You pass these properties, not strings, to filters and selects.
import { eq } from "drizzle-orm";
// users.id and users.name are typed column objects
const rows = await db
.select()
.from(users)
.where(eq(users.id, 1));Unknown Column = Compile Error
Because columns are real properties, a typo is caught immediately. There is no stringly-typed escape hatch.
await db.select().from(users).where(eq(users.idd, 1));
// ^^^^
// Error: Property "idd" does not exist on the users table.Typed Comparison Operands
Operators like eq are generic over the column type. Comparing a number column to a string is a type error.
eq(users.age, 30); // ok: age is number
eq(users.age, "thirty"); // Error: string is not assignable to numberSelecting Specific Columns
Pass an object whose values are column references to project a subset. The keys you choose become the result keys.
const partial = await db
.select({ id: users.id, name: users.name })
.from(users);
// result rows: { id: number; name: string }[]Rejecting Columns From Other Tables
The select map is constrained to columns of the queried table(s). Referencing a column from an unrelated table fails to compile.
await db
.select({ title: posts.title }) // posts not in this query
.from(users);
// Error: posts.title is not part of the FROM clause.Composable Conditions
Conditions combine with and, or, not. Each piece stays typed, so a malformed condition is caught even deep in a tree.
import { and, gt, eq } from "drizzle-orm";
const q = db.select().from(users).where(
and(gt(users.age, 18), eq(users.isAdmin, false))
);Ordering and Limiting
orderBy also takes typed column references, so you cannot sort by a column that is not in the table.
import { desc } from "drizzle-orm";
await db.select().from(users).orderBy(desc(users.age)).limit(10);How Rejection Works
The builder is generic over the table type. The where and select signatures only accept values of type Column<TTable>, so the compiler structurally rejects anything else.
// Conceptual signature
declare function select<T>(
table: T,
cols: { [k: string]: ColumnOf<T> }
): Query;Inserts Are Typed Too
Insert values are checked against the insert model. Missing required fields or wrong value types are compile errors before any SQL runs.
await db.insert(users).values({
name: "Ada",
isAdmin: false,
// missing fields would error; extra unknown keys error too
});Why It Helps
Most ORM bugs come from a renamed or mistyped column discovered only at runtime. A type-safe builder turns those into red squiggles in your editor, long before deployment.
Quick Check
Verify your grasp of type-safe query construction.
Recap
Type-safe query construction uses typed column references instead of strings. Unknown columns, wrong operand types, and columns from tables not in the FROM clause all become compile errors. The builder is generic over the table, so the type system structurally enforces validity.
Frequently asked questions
Is the “Type-Safe Query Construction” lesson free?
Yes — the full text of “Type-Safe Query Construction” is free to read here on the web, and the TypeScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.
What will I learn in “Type-Safe Query Construction”?
Build queries that reject invalid columns at compile time. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start TypeScript Academy?
No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Type-Safe Query Construction” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this TypeScript Academy lesson?
Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Schema-to-Type Mapping
- Type-Safe Query Construction
- Inferring Query Result Shapes
- Relations and Joins with Types