joshpachner
joshpachner•5mo ago

Is there a way to get around the Id<"tablename">

Ive been looking in the docs trying to figure this out so that using convex is a lil more type friendly. Situation: Ideally want to keep using the Id<"tablename"> when defining my tables in convex's schema. BUT throughout the rest of my app, i dont want to be constantly having to " as Id<"tablename"> " for all my relational fields I've tried the " Doc<"tablename">
but that still returns fields with the Id<"tablename"> (see screenshot) Anyone got a solution for this?
No description
12 Replies
joshpachner
joshpachnerOP•5mo ago
Ok my buddy came up with something like this
import type { Doc, Id, TableNames } from "./convex/_generated/dataModel";


export type StripIds<T extends object> = {
[key in keyof T]: T[key] extends Id<TableNames> ? string : T[key];
};

export type DocStrippedWithSystemFields<T extends TableNames> =StripIds<Doc<T>>;

export type DocStripped<T extends TableNames> = Omit<DocStrippedWithSystemFields<T>, "_id" | "_creationTime">
import type { Doc, Id, TableNames } from "./convex/_generated/dataModel";


export type StripIds<T extends object> = {
[key in keyof T]: T[key] extends Id<TableNames> ? string : T[key];
};

export type DocStrippedWithSystemFields<T extends TableNames> =StripIds<Doc<T>>;

export type DocStripped<T extends TableNames> = Omit<DocStrippedWithSystemFields<T>, "_id" | "_creationTime">
lee
lee•5mo ago
can you show more of the code causing the error? normally you want your code to keep the typesafety end-to-end; you shouldn't need to cast often
joshpachner
joshpachnerOP•5mo ago
this nightmare of a thing
No description
lee
lee•5mo ago
huh. Have you considered using v.union(v.literal(""), v.id("tcgs")) in your schema, if that's supposed to be a valid document?
joshpachner
joshpachnerOP•5mo ago
but then that would allow it to be "nullable"
lee
lee•5mo ago
It looks to me like it is nullable. The code is saying that tcgId: "" can be used to construct a valid Doc<"tournaments"> your workaround looks fine to me, btw 🙂 you could also use const fakeId = "" as Id<any> and use that everywhere
joshpachner
joshpachnerOP•5mo ago
That's just initializing the state (svelte app). I assume if we try to save that empty string to convex that it would then throw an error because "" is not a valid id for the TCGs table
lee
lee•5mo ago
What is the state used for? I still don't understand why having an invalid Doc<"tournaments"> in svelte state would be useful. Would it be possible to do let tournamentState = $state<Doc<"tournaments">[]>([]); instead?
joshpachner
joshpachnerOP•5mo ago
that screenshot i sent ya is using the convex's Doc<>. And so my typescript throws a nightmare of type insecurities, because im initializing my state with an empty string (because the user has not selected the typeId yet). But using my work around causes no issues. I would recommend adding this workaround to the convex docs for otherss
lee
lee•5mo ago
I still don't understand how you're using this state, and why it's okay to initialize the values with the wrong types. It's like doing let mystring = $state<string>(0.0); it's not going to work without casting
joshpachner
joshpachnerOP•5mo ago
because Id<"tablename"> is fundamentally just a string. And an <input type="text"> is not Id<"tablename"> rather its a string. Correct me if im wrong, but Id<"tablename"> only has importance at the time of writing to the database to enforce relationality. On the client side having to cast it to Id<"tablename"> every time its being passed doesn't actually enforce relationality. So its pointless to not just treat it as a string type.
lee
lee•5mo ago
no, Id<"tablename"> isn't just a string. it's a subtype of strings that has a minimum and maximum length, only allows certain characters, and has some other restrictions. So the empty string is never a valid Id<"tablename">, just like 1.5 isn't a valid BigInt. Furthermore, there actually is not runtime check that enforces relationality. You can hypothetically construct an Id<"tablename"> that has never existed before, and it will pass all arg and schema validation.

Did you find this page helpful?