RJ
RJ•16mo ago

Codegen typings break when `exactOptionalPropertyTypes` is true

https://www.typescriptlang.org/tsconfig#exactOptionalPropertyTypes I'd like to turn it on for this library: https://github.com/Effect-TS/schema#requirements, and just because it's more strict.
16 Replies
RJ
RJOP•16mo ago
I don't have time right now to collect more details, but the gist of what I noticed is that some generated types are inferred to be unknown with that option turned on, whereas without it they are correct.
ballingt
ballingt•16mo ago
We hear you. I've chatted with other authors of TypeScript libraries about this, it's doable but we'd need to make sure the library works with this setting both on and off because most of our users don't use it. Helpful to see it's required for this library, I hadn't seen that before
RJ
RJOP•16mo ago
Technically not required, but recommended (so doesn't stop me from using it). But sounds great, thanks for considering 🙂
ballingt
ballingt•16mo ago
I do like writing TypeScript with this on, it feels like a whole different language Lee just did a quick attempt at a repro and didn't see this, I'll take a look later but if you have something repro-able (maybe it's a to do with types you're using in a function?) it could help
RJ
RJOP•16mo ago
I’ll see if I have some time later today or tomorrow to share some more data!
ballingt
ballingt•16mo ago
Thank you!
RJ
RJOP•16mo ago
Here's a simple example that might be easy to reproduce. With exactOptionalPropertyTypes turned on, the following code:
db
.query("users")
.withIndex("by_clerk_user_id", (q) =>
q.eq("clerkUserId", clerkUserId),
)
.unique()
db
.query("users")
.withIndex("by_clerk_user_id", (q) =>
q.eq("clerkUserId", clerkUserId),
)
.unique()
Is inferred to have a type of:
Promise<{
[x: string]: Value;
_id: Id<"users">;
} | null>
Promise<{
[x: string]: Value;
_id: Id<"users">;
} | null>
Where what I would expect is:
Promise<{
_id: Id<"users">;
} | null>
Promise<{
_id: Id<"users">;
} | null>
Promise<{
_id: Id<"users">;
_creationTime: number;
clerkUserId?: string | undefined;
// and more fields
} | null>
Promise<{
_id: Id<"users">;
_creationTime: number;
clerkUserId?: string | undefined;
// and more fields
} | null>
Adam Harris
Adam Harris•7mo ago
Hi @RJ @ballingt I'm just getting started with convex, looking to use effect-ts schema also and have just come across this issue. Is the recommended workaround still just to keep the exactOptionalPropertyTypes flag set to false?
RJ
RJOP•7mo ago
Hey @Adam Harris—I don't have any updates on my side, I still use Schema with exactOptionalPropertyTypes set to false
Adam Harris
Adam Harris•7mo ago
@RJ thanks for the confirmation! Maybe I'll just stick with Zod schemas for now then, since the integration with zod seems good...
RJ
RJOP•7mo ago
The integration with Zod and Convex is definitely better at the moment, but using Schema with exactOptionalPropertyTypes set to false is also only a minor downside, in my experience! I think either one is a good choice 🙂 But if you're not using the rest of the Effect ecosystem, maybe Zod is the better move
ballingt
ballingt•7mo ago
@RJ I'm adding tests that we can run these tests under alternate tsconfig.json settings to get some things right, here's one example:
No description
ballingt
ballingt•7mo ago
We need to know that our library works with this setting off as well, but we can start trying to make the experience with it on good too. I'd love to hear what else breaks if you happen to run into it — it's not a priority right now but at least for now for all types we write going forward we can make these work.
RJ
RJOP•7mo ago
Sure thing, I'll test it out again when I have a chance! Just turned this on and I'm seeing similar errors as I did before, but this is on convex@0.12.1. Should I try this on the latest alpha version? Or wait for a new release? Or would it be helpful to see more of the errors I'm seeing right now?
ballingt
ballingt•7mo ago
Not much has changed yet, sounds like it's obvious issues so maybe this isn't that helpful yet. Thanks for the reminder, I didn't realize how broken it was.
erquhart
erquhart•6mo ago
+1 on this, there's some type safety we simply don't get without this setting Zod and Effect aside, here's a basic usage example. The type errors in this mutation won't get caught by the compiler and will fail at runtime.
const schema = defineTable({
myTable: { field: v.string() },
})

type PatchInput = Partial<Doc<'myTable'>>

export const myMutation = mutation((ctx, args) => {
const patch: PatchInput = {
field: undefined, // no error here
}
ctx.db.patch(args.id, patch) // no error here either
})
const schema = defineTable({
myTable: { field: v.string() },
})

type PatchInput = Partial<Doc<'myTable'>>

export const myMutation = mutation((ctx, args) => {
const patch: PatchInput = {
field: undefined, // no error here
}
ctx.db.patch(args.id, patch) // no error here either
})
I believe the flag would produce errors in both of the denoted lines here.

Did you find this page helpful?