Recursive + `any` schema types
Related questions:
- Is there any way to define a recursive
SchemaType
?
- Is there any way to describe an untyped field in a [typed] schema? Consider:
10 Replies
More good questions!
Yeah, there is no way to do a recursive schema fields, but you can use the workaround from https://discord.com/channels/1019350475847499849/1037457654664134808/1037468984154525847 to create other recursive types.
Similarly, you can simulate an
any
with something like:
Same warning as with JSON that this might break in future versions of Convex.
Also be aware that this allows you to attempt to serialize types that Convex doesn't support (ex new Date()
, undefined
).Interesting, good to know!
I guess what I'd really want then is an "any valid
SchemaType
construction" SchemaType
Yeah, for sure. I think this is somewhat tricky/inconvenient to do in TypeScript. We could build an
s.any
that is a union of every type, but then you'd have to explicitly check the type of it before using the value. For example you couldn't pass it to a function that expects a string until you check that it's a string.
But yeah I think having some type of any
construct would be nice so you can bail out of using a schema for part of your data model.It would be useful particularly on the sending side—so that I can send a value to a Convex endpoint and know that it won't fail to persist. In other words, it would be nice to know if my value of type
T
extends
AnyConvexType
. On the receiving side I am probably shunting it off to some library or something which takes any
or unknown
, or am doing some runtime validation with something like io-ts
or zod
, which I think would not be a problem as well
A user could always cast it as any
themselves also, but maybe better to leave that to them if they want to in particular places?Got it. Makes sense for your use case.!This is also kinda hard to do in TypeScript because TypeScript always allows objects to have extra properties and those could contain types that Convex doesn't support.
But I think talking about this I'm also excited about having an
s.any()
that just bails out of using a schema for that part. I suspect that would make schemas easier to adopt.Ah yes you’re right, good point! Reflecting on it more though, I think my example
T extends AnyConvexType
was just bad/misleading—I don’t think a user (or I, at least) would interact with AnyConvexType
like that. I think that I would have something of MyType
and would try to pass it as an argument to db.insert
. In that case, I think TypeScript would just do it’s classic structural type comparison thing and all would work as hoped?If not, there are also utility types like https://github.com/sindresorhus/type-fest/blob/main/source/jsonify.d.ts that might help?
GitHub
type-fest/jsonify.d.ts at main · sindresorhus/type-fest
A collection of essential TypeScript types. Contribute to sindresorhus/type-fest development by creating an account on GitHub.
I’m not exactly sure though
Anyways yeah, some form of “type hole” in a schema definition seems like it could be nice, however that’s effected!
Following up here, we now have s.any() to replace schemaAny
We also now have
{ strict: false }
as a parameter to defineSchema
if you want a partially defined table, or to not have to specify all your tables. I also just wrote a blog post on using zod with Convex: https://stack.convex.dev/wrappers-as-middleware-zod-validationZod Validation: Wrappers as “Middleware”
Function validation is important for a production app because you can’t always control which clients are talking to your server. See how to use zod to...