whoami
whoami2y ago

Use `v.` schema to validate object types?

How do I use the v. schema defined in schema.ts and use it to validate typescript object types? So I do not need to define a zod schema again, or maybe you will support zod schema in the future?
7 Replies
lee
lee2y ago
The schema.ts should automatically validate typescript object types. Once you have defined your schema.ts and run npx convex dev (or npx convex codegen), the types for db.insert, db.get, db.query, etc. should all use the schema types. If it's not working for you, could you share a repro?
lee
lee2y ago
If you want to use the type directly, you can import { Doc } from "../convex/_generated/dataModel"; as described in https://docs.convex.dev/database/schemas#typescript-types
Schemas | Convex Developer Hub
Schema validation keeps your Convex data neat and tidy. It also gives you end-to-end TypeScript type safety!
alexcole
alexcole2y ago
Did you want to reuse this validator outside of argument validation and schemas? That's not supported right now, but it is something we could add in the future.
whoami
whoamiOP2y ago
yes I want to validate it outside of schema file, do you think you can reuse zod’s schema as it is more common? Basically I have a union type on a particular field within which different types will have their individual rendering logic that requires the type validation on the react side
ian
ian2y ago
It may be possible to make a tool to derive a convex schema from a zod object, but one concern would be that it wouldn’t enforce the zod rules out of the gate- if you had a string of max length 3, you could do that validation client side, but when we turned it into a convex schema it’d just be v.string(). Would that still be useful? For input validation shared with the client you can use my withZod helper, but it doesn’t convert to a schema yet. And when we have the client-side convex validator, would it be useful enough if it only checked types, vs. all the zod validators like email, phone, etc?
alexcole
alexcole2y ago
Yeah, for right now there isn't a good way to share validators between your schema and your UI. The best approach is probably to duplicate between Convex validators and Zod (or skip the Convex schema validation entirely and call your Zod validator just before db.insert and db.replace). But thanks for the feedback! I'll count this as a vote for Zod support and/or the ability to call Convex validators from JS. Oh actually, one more idea: if you use the discriminated union pattern, you don't actually need the validator to tell which case of the union you're in. I'm imagining something like:
// In your schema:
const shapeValidator = v.union(
v.object({
type: "triangle",
sideLength: v.number()
}),
v.object({
type: "circule",
radius: v.number()
}),
);

defineSchema({
shapes: defineTable(shapeValidator)
});

// In your UI

function ShapeComponent({ shape }: { shape: Document<"shapes"> })
if (shape.type == "triangle") {
// render triangle here
// TypeScript will narrow the type to `{type: "triangle", sideLength: number}`
} else if (...)
}
// In your schema:
const shapeValidator = v.union(
v.object({
type: "triangle",
sideLength: v.number()
}),
v.object({
type: "circule",
radius: v.number()
}),
);

defineSchema({
shapes: defineTable(shapeValidator)
});

// In your UI

function ShapeComponent({ shape }: { shape: Document<"shapes"> })
if (shape.type == "triangle") {
// render triangle here
// TypeScript will narrow the type to `{type: "triangle", sideLength: number}`
} else if (...)
}
Idk if this works for your use case
whoami
whoamiOP2y ago
ah yes having an additional field definitely helps, I am using this now

Did you find this page helpful?