#why is type inference ret*rded

8 messages · Page 1 of 1 (latest)

inland compass
#

export const getWorlds = query({
args: {},
handler: async (ctx, args) => {
const userId = await getAuthUserId(ctx);
if (userId === null) {
return { worlds: [] };
}
const profile = await ctx.runQuery(internal.functions.getProfile, {
userId: userId,
});
if (profile === null) {
return { worlds: [] };
}
const profileId = profile._id;
const worlds = await ctx.db.query("worlds").collect();
const final = worlds.filter((world) =>
world.participants.includes(profileId),
);
// return {
// worlds: final,
// };
},
});
this works (commented out). if the last line is not commented out, i get

'final' is declared but its value is never read.ts(6133)
⌘+click to open in new tab
'final' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)
⌘+click to open in new tab
const final: any

what is going on?

clear crescentBOT
#

Hi @inland compass. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

The TypeScript type inference issue you're seeing—where returning the result of ctx.runQuery causes the type of final (and sometimes the whole handler) to become any—is a known problem in Convex projects. This happens due to circular type inference: when the return type of your query or action depends on another Convex function (like ctx.runQuery or ctx.runMutation), TypeScript can't resolve the types and falls back to any, or gives you errors like "implicitly has type 'any'" or "is referenced directly or indirectly in its own initializer" Dealing with circular type inference.

Why does this happen?

  • When you return the result of a Convex function (like ctx.runQuery) directly or use its result in your return value, TypeScript tries to infer the type by looking at the other function. But if those functions reference each other (directly or indirectly), TypeScript can't resolve the types and gives up, resulting in any or related errors.

How to fix it?
You need to explicitly annotate the return type of your handler function or the result variable. For example:

export const getWorlds = query({
  args: {},
  handler: async (ctx, args): Promise<{ worlds: Doc<"worlds">[] }> => {
    const userId = await getAuthUserId(ctx);
    if (userId === null) {
      return { worlds: [] };
    }
    const profile = await ctx.runQuery(internal.functions.getProfile, {
      userId: userId,
    });
    if (profile === null) {
      return { worlds: [] };
    }
    const profileId = profile._id;
    const worlds = await ctx.db.query("worlds").collect();
    const final = worlds.filter((world) =>
      world.participants.includes(profileId),
    );
    return {
      worlds: final,
    };
  },
});

Or, you can annotate the type of final explicitly:

#
const final: Doc<"worlds">[] = worlds.filter(...);

This tells TypeScript exactly what to expect, breaking the circular inference and restoring type safety. This is a common workaround recommended in the Convex documentation and by Convex support staff Dealing with circular type inference Returning response from runQuery in a query breaks typescript.

Summary:
This is not a bug in Convex, but a limitation of TypeScript's type inference with circular dependencies. Explicitly annotating your handler's return type or the result variable will resolve the issue.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@inland compass Kapa.ai is still learning and improving, please let me know how I did by reacting below.

inland compass
#

@clear crescent that worked ty

clear crescentBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

You're welcome! Explicitly annotating the return type of your handler or the result variable is the recommended solution for these TypeScript inference issues in Convex, especially when using ctx.runQuery or ctx.runMutation. This approach is documented and supported by the Convex team as the standard workaround for circular type inference problems in Convex projects Dealing with circular type inference. If you run into similar issues elsewhere, applying explicit type annotations should help.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: