Eklayzia
Eklayzia•3w ago

No query type safety

Hello, I'm having trouble with why I'm not seeing proper type safety. In my code:
const objects = useQuery(api.schema.objects.getObjects);
const objects = useQuery(api.schema.objects.getObjects);
objects is type any. My schema:
import { authTables } from "@convex-dev/auth/server";
import { defineSchema } from "convex/server";
import { properties } from "./schema/properties";
import { objects } from "./schema/objects";
import { entities } from "./schema/entities";
import { entityValues } from "./schema/entityValues";

/**
* Convex Auth requires indexes defined on `authTables`.
*
* Objects are user defined.
* Objects have user defined properties.
* Entities are instances of objects with EntityValues for their properties.
*/
export default defineSchema({
...authTables,
objects,
properties,
entities,
entityValues,
});
import { authTables } from "@convex-dev/auth/server";
import { defineSchema } from "convex/server";
import { properties } from "./schema/properties";
import { objects } from "./schema/objects";
import { entities } from "./schema/entities";
import { entityValues } from "./schema/entityValues";

/**
* Convex Auth requires indexes defined on `authTables`.
*
* Objects are user defined.
* Objects have user defined properties.
* Entities are instances of objects with EntityValues for their properties.
*/
export default defineSchema({
...authTables,
objects,
properties,
entities,
entityValues,
});
schema/objects.ts
import { v } from "convex/values";
import { defineTable } from "convex/server";
import { query } from "@/_generated/server";
import { mutation } from "@/_generated/server";
import { Doc, Id } from "@/_generated/dataModel";

export const objects = defineTable({
name: v.string(),
description: v.string(),
user: v.string(),
icon: v.string(),
}).index("by_user", ["user"]);

export const getObjects = query({
handler: async (ctx): Promise<Doc<"objects">[]> => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) {
throw new Error("Unauthenticated");
}
const userId = identity.subject;
return await ctx.db.query("objects")
.withIndex("by_user", (q) => q.eq("user", userId))
.collect();
},
});
import { v } from "convex/values";
import { defineTable } from "convex/server";
import { query } from "@/_generated/server";
import { mutation } from "@/_generated/server";
import { Doc, Id } from "@/_generated/dataModel";

export const objects = defineTable({
name: v.string(),
description: v.string(),
user: v.string(),
icon: v.string(),
}).index("by_user", ["user"]);

export const getObjects = query({
handler: async (ctx): Promise<Doc<"objects">[]> => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) {
throw new Error("Unauthenticated");
}
const userId = identity.subject;
return await ctx.db.query("objects")
.withIndex("by_user", (q) => q.eq("user", userId))
.collect();
},
});
Convex dev is running and says everything is ready. What's going on here? It's all [x: string]: any Imports
import { useQuery } from "convex/react";
import { api } from "../../../../convex/_generated/api";
import { useQuery } from "convex/react";
import { api } from "../../../../convex/_generated/api";
No description
8 Replies
Eklayzia
EklayziaOP•3w ago
Sorry I suppose I shouldn't be destructure it, though I still don't see a type.
No description
homanp
homanp•3w ago
const data: Doc<"objects">[] = userQuery(...); wouldn't this work?
Zwyx
Zwyx•3w ago
I'm surprised by the type Promise<Doc<"objects">[]> in the getObjects query. My queries don't have any type here, it's all automatic.
Eklayzia
EklayziaOP•3w ago
It would, though my understanding was that this should be automatic 🤔 Though this should actually be Doc… | undefined right? Taking a look… I removed that bit; I'm not sure why I had that only for the object queries/mutation functions but not the others... my brain is fried. However, there are no improvements, and the other queries are still all any. schema/entities
export const getEntity = query({
args: {
entityId: v.id("entities"),
},
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) {
throw new Error("Unauthenticated");
}

return await ctx.db.get(args.entityId);
},
});
export const getEntity = query({
args: {
entityId: v.id("entities"),
},
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) {
throw new Error("Unauthenticated");
}

return await ctx.db.get(args.entityId);
},
});
Has type:
const getEntity: RegisteredQuery<"public", {
entityId: Id<"entities">;
}, Promise<{
_id: Id<"entities">;
_creationTime: number;
name: string;
user: string;
objectId: Id<"objects">;
} | null>>
const getEntity: RegisteredQuery<"public", {
entityId: Id<"entities">;
}, Promise<{
_id: Id<"entities">;
_creationTime: number;
name: string;
user: string;
objectId: Id<"objects">;
} | null>>
But in a component:
import { useQuery } from "convex/react";
import { api } from "../../../../convex/_generated/api";
// ...
const entity = useQuery(api.schema.entities.getEntity, { entityId });
import { useQuery } from "convex/react";
import { api } from "../../../../convex/_generated/api";
// ...
const entity = useQuery(api.schema.entities.getEntity, { entityId });
Has type any for entity.
Eklayzia
EklayziaOP•3w ago
For clarity, this is another project I had in the past. Convex here had automatic typings 🤔.
export const getEntityName = query({
args: {
entityId: v.id('entities'),
},
handler: async (ctx, args) => {
return await ctx.db
.query('nameComponents')
.filter((q) => q.eq(q.field('entityId'), args.entityId))
.first();
},
});
export const getEntityName = query({
args: {
entityId: v.id('entities'),
},
handler: async (ctx, args) => {
return await ctx.db
.query('nameComponents')
.filter((q) => q.eq(q.field('entityId'), args.entityId))
.first();
},
});
Not sure what the difference is...
No description
Eklayzia
EklayziaOP•3w ago
I'm noticing that in my previous project that I made a few months ago, there is no tsconfig file in the convex/ directory. The current one has one, though it's generated.
{
/* This TypeScript project config describes the environment that
* Convex functions run in and is used to typecheck them.
* You can modify it, but some settings required to use Convex.
*/
"compilerOptions": {
/* These settings are not required by Convex and can be modified. */
"allowJs": true,
"strict": true,
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,

/* These compiler options are required by Convex */
"target": "ESNext",
"lib": ["ES2021", "dom"],
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"isolatedModules": true,
"noEmit": true,
"paths": {
"@/*": ["./*"]
}
},
"include": ["./**/*"],
"exclude": ["./_generated"]
}
{
/* This TypeScript project config describes the environment that
* Convex functions run in and is used to typecheck them.
* You can modify it, but some settings required to use Convex.
*/
"compilerOptions": {
/* These settings are not required by Convex and can be modified. */
"allowJs": true,
"strict": true,
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,

/* These compiler options are required by Convex */
"target": "ESNext",
"lib": ["ES2021", "dom"],
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"isolatedModules": true,
"noEmit": true,
"paths": {
"@/*": ["./*"]
}
},
"include": ["./**/*"],
"exclude": ["./_generated"]
}
I deleted it, and the type safety is working now. This doesn't seem right: "You can modify it, but some settings required to use Convex."
lee
lee•3w ago
do you know where the
"paths": {
"@/*": ["./*"]
}
"paths": {
"@/*": ["./*"]
}
part of that tsconfig came from? I don't remember seeing it in any convex tutorials
Eklayzia
EklayziaOP•3w ago
I added it for easier imports. I put the config file back (including the paths I added), and the typings are working now. I'm quite confused. This isn't the first time I've restarted my IDE, either. Well, I'm not sure what I did to be honest besides deleting that file and adding it back in... Thanks for everyone's help; hopefully, it doesn't break again. Oh, actually, the paths thing was breaking it. Huh, it seems like the tsconfig from the overall project cannot reconcile with the paths configured in the convex tsconfig. I switched the imports in the convex schema back from relative to @, and it broke 🥲. Thanks Lee! I do wish it were possible to use paths though 🤔 Nevermind, got it to work. Just have to configure the same path key to the relative values to each tsconfig, in both files.

Did you find this page helpful?