Struggling to use Zod with Drizzle... Type errors around |undefined

import { serial, text, timestamp, pgTable } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";

export const users = pgTable("users", {
id: serial("id"),
name: text("name"),
email: text("email"),
password: text("password"),
role: text("role").$type<"admin" | "user">(),
createdAt: timestamp("created_at"),
updatedAt: timestamp("updated_at"),
});

export const insertUserSchema = createInsertSchema(users, {
role: z.enum(["admin", "user"])
});
//This is supposed to be what we get from the POST request, it omits ID and createdAt/updatedAt fields
export const apiInsertUserSchema = insertUserSchema.omit({ id: true, createdAt: true, updatedAt: true });

export const selectUserSchema = createSelectSchema(users);
import { serial, text, timestamp, pgTable } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";

export const users = pgTable("users", {
id: serial("id"),
name: text("name"),
email: text("email"),
password: text("password"),
role: text("role").$type<"admin" | "user">(),
createdAt: timestamp("created_at"),
updatedAt: timestamp("updated_at"),
});

export const insertUserSchema = createInsertSchema(users, {
role: z.enum(["admin", "user"])
});
//This is supposed to be what we get from the POST request, it omits ID and createdAt/updatedAt fields
export const apiInsertUserSchema = insertUserSchema.omit({ id: true, createdAt: true, updatedAt: true });

export const selectUserSchema = createSelectSchema(users);
import type { FastifyInstance } from "fastify";
// Import drizzle schema
import { users, insertUserSchema, apiInsertUserSchema } from "@api/db/schemas";
import { db } from "@api/db";
import { Logger } from "@api/utils";



export const testRoutes = (fastify: FastifyInstance, _: unknown, done: () => void) => {
fastify.get("/", async (request, response) => {
const vists = 0;
console.log(request);
response.send({
hello: "world",
vists,
});
});

fastify.get("/users", async (request, response) => {
const allUsers = await db.select().from(users);
console.log(users);
response.send(allUsers);
});

fastify.post("/users", async (request, response) => {
console.log(request);
try {
let parsedRequest = apiInsertUserSchema.parse(request.body);
console.log("request body: ", request.body);
console.log("parsed request: ", parsedRequest);
await db.insert(users).values(parsedRequest);
} catch (error) {
console.log(error);
Logger.error("POST /users", `${error}`);
response.status(400).send({ error: "Invalid request body" });
}

});
import type { FastifyInstance } from "fastify";
// Import drizzle schema
import { users, insertUserSchema, apiInsertUserSchema } from "@api/db/schemas";
import { db } from "@api/db";
import { Logger } from "@api/utils";



export const testRoutes = (fastify: FastifyInstance, _: unknown, done: () => void) => {
fastify.get("/", async (request, response) => {
const vists = 0;
console.log(request);
response.send({
hello: "world",
vists,
});
});

fastify.get("/users", async (request, response) => {
const allUsers = await db.select().from(users);
console.log(users);
response.send(allUsers);
});

fastify.post("/users", async (request, response) => {
console.log(request);
try {
let parsedRequest = apiInsertUserSchema.parse(request.body);
console.log("request body: ", request.body);
console.log("parsed request: ", parsedRequest);
await db.insert(users).values(parsedRequest);
} catch (error) {
console.log(error);
Logger.error("POST /users", `${error}`);
response.status(400).send({ error: "Invalid request body" });
}

});
I'm attemping to perform validation and inserting with Zod... however, I'm getting errors around the fact the generated schema includes |undefined in each of the rows... Is there a way around this? Sorry for the noob question.
4 Replies
codelilac
codelilacOP5mo ago
for added context:
[{
"resource": "/Users/brandonclark/Repositories/rbp_backend/src/routes/test.ts",
"owner": "typescript",
"code": "2769",
"severity": 8,
"message": "No overload matches this call.\n Overload 1 of 2, '(value: { name: string | SQL<unknown> | Placeholder<string, any>; email: string | SQL<unknown> | Placeholder<string, any>; password: string | SQL<unknown> | Placeholder<...>; role: \"admin\" | ... 2 more ... | Placeholder<...>; createdAt: Date | ... 1 more ... | Placeholder<...>; updatedAt: Date | ... 1 more ... | Placeholder<...>; id?: number | ... 1 more ... | Placeholder<...>; }): PgInsertBase<...>', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ name: string | SQL<unknown> | Placeholder<string, any>; email: string | SQL<unknown> | Placeholder<string, any>; password: string | SQL<unknown> | Placeholder<string, any>; role: \"admin\" | ... 2 more ... | Placeholder<...>; createdAt: Date | ... 1 more ... | Placeholder<...>; updatedAt: Date | ... 1 more ... | Pla...'.\n Overload 2 of 2, '(values: { name: string | SQL<unknown> | Placeholder<string, any>; email: string | SQL<unknown> | Placeholder<string, any>; password: string | SQL<unknown> | Placeholder<...>; role: \"admin\" | ... 2 more ... | Placeholder<...>; createdAt: Date | ... 1 more ... | Placeholder<...>; updatedAt: Date | ... 1 more ... | Placeholder<...>; id?: number | ... 1 more ... | Placeholder<...>; }[]): PgInsertBase<...>', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ name: string | SQL<unknown> | Placeholder<string, any>; email: string | SQL<unknown> | Placeholder<string, any>; password: string | SQL<unknown> | Placeholder<string, any>; role: \"admin\" | ... 2 more ... | Placeholder<...>; createdAt: Date | ... 1 more ... | Placeholder<...>; updatedAt: Date | ... 1 more ... | Pla...'.",
"source": "ts",
"startLineNumber": 31,
"startColumn": 37,
"endLineNumber": 31,
"endColumn": 49
}]
[{
"resource": "/Users/brandonclark/Repositories/rbp_backend/src/routes/test.ts",
"owner": "typescript",
"code": "2769",
"severity": 8,
"message": "No overload matches this call.\n Overload 1 of 2, '(value: { name: string | SQL<unknown> | Placeholder<string, any>; email: string | SQL<unknown> | Placeholder<string, any>; password: string | SQL<unknown> | Placeholder<...>; role: \"admin\" | ... 2 more ... | Placeholder<...>; createdAt: Date | ... 1 more ... | Placeholder<...>; updatedAt: Date | ... 1 more ... | Placeholder<...>; id?: number | ... 1 more ... | Placeholder<...>; }): PgInsertBase<...>', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ name: string | SQL<unknown> | Placeholder<string, any>; email: string | SQL<unknown> | Placeholder<string, any>; password: string | SQL<unknown> | Placeholder<string, any>; role: \"admin\" | ... 2 more ... | Placeholder<...>; createdAt: Date | ... 1 more ... | Placeholder<...>; updatedAt: Date | ... 1 more ... | Pla...'.\n Overload 2 of 2, '(values: { name: string | SQL<unknown> | Placeholder<string, any>; email: string | SQL<unknown> | Placeholder<string, any>; password: string | SQL<unknown> | Placeholder<...>; role: \"admin\" | ... 2 more ... | Placeholder<...>; createdAt: Date | ... 1 more ... | Placeholder<...>; updatedAt: Date | ... 1 more ... | Placeholder<...>; id?: number | ... 1 more ... | Placeholder<...>; }[]): PgInsertBase<...>', gave the following error.\n Argument of type 'unknown' is not assignable to parameter of type '{ name: string | SQL<unknown> | Placeholder<string, any>; email: string | SQL<unknown> | Placeholder<string, any>; password: string | SQL<unknown> | Placeholder<string, any>; role: \"admin\" | ... 2 more ... | Placeholder<...>; createdAt: Date | ... 1 more ... | Placeholder<...>; updatedAt: Date | ... 1 more ... | Pla...'.",
"source": "ts",
"startLineNumber": 31,
"startColumn": 37,
"endLineNumber": 31,
"endColumn": 49
}]
this appears to be an issue with Zod itself, what a bummer
cenuijza
cenuijza5mo ago
Dunno, I tried your schema and it works just fine.
let parsedRequest = apiInsertUserSchema.parse({});
await db.insert(users).values(parsedRequest);
let parsedRequest = apiInsertUserSchema.parse({});
await db.insert(users).values(parsedRequest);
gives me no TS errors. The only way I can get the same TS error as you is if somehow parsedRequest has unknown type ... e.g.
await db.insert(users).values(parsedRequest as unknown);
await db.insert(users).values(parsedRequest as unknown);
I don't know how that would happen, unless VSCode is confused, in which case I would restart the TS language server (or just VSCode) The error says Argument of type 'unknown' is not assignable to parameter of type '{ name ..., so somehow TS thinks that your parsedRequest variable has type unknown
codelilac
codelilacOP5mo ago
In your TS config, do you have exactOptionalPropertyTypes enabled? This is the flag that causes the issue By default, Zod includes | undefined on fields with Zod.Optional(), this causes an issue since there’s a difference between a type that is set to undefined and getting ‘undefined’ from a variable, which is what that flag enforces checks for. I’ve since switched to Drizzle Typebox which is quite a bit less headache and had this flag in mind from the get go :)
cenuijza
cenuijza5mo ago
Ah I see ... I don't have that flag
Want results from more Discord servers?
Add your server