#Type Issue with gameId in Convex Query

66 messages · Page 1 of 1 (latest)

haughty tusk
#

Hi, I have an issue with TypeScript types in Convex.

I'm looking at the example code in the Fast5 repo:

import { v } from "convex/values";
import { query } from "../_generated/server";
import { withUser } from "../wrappers/withUser";

export default query({
  args: {
    gameId: v.id("games"),
  },
  handler: withUser(async ({ db, user }, { gameId }) => { ... }),
});

In the Fast5 repo, gameId has the proper type:

(parameter) gameId: Id<"games">

However, when I use the exact same code in my repo, the type of gameId is inferred as:

(parameter) gameId: any

I’m wondering why this is happening. Could this be related to TypeScript configuration, Convex version differences, or something else?

Any help would be appreciated! Thanks! 😊

fluid patrolBOT
#

Thanks for posting in #1088161997662724167.
Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets.

    - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.)
    - Use [search.convex.dev](https://search.convex.dev) to search Docs, Stack, and Discord all at once.
    - Additionally, you can post your questions in the Convex Community's #1228095053885476985 channel to receive a response from AI.
    - Avoid tagging staff unless specifically instructed.

    Thank you!
haughty tusk
#

withUser wrapper is the same as in Fast5 repo

runic cove
#

Usually this is because of a typescript error in another file

haughty tusk
#

Thanks for the response! I checked the Convex logs, and I'm seeing:

✔ 22:24:30 Convex functions ready! (7s)

I don’t see any TypeScript errors in the logs.

Could there be another reason why gameId is inferred as any?

runic cove
#

One function having circular inference and therefore inferring any can make lots of types be any. When you say exact same code, do you have the same libraries installed, is this just a copy of that repo? Or you have your own code too?

#

Somewhere you have a type that can't be inferred, or some types that are broken (but apparently not in a way that causes a type error)

haughty tusk
#

while building i did got one errror can this be the case?

info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
   Linting and checking validity of types  ..Failed to compile.

./node_modules/convex-helpers/index.ts:16:22
Type error: Type 'Iterable<FromType>' can only be iterated through when using the '--downlevelIteration' flag or with a '--target' of 'es2015' or higher.

  14 |   let index = 0;
  15 |   list = await list;
> 16 |   for (const item of list) {
     |                      ^
  17 |     promises.push(asyncTransform(item, index));
  18 |     index += 1;
  19 |   }
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
runic cove
#

ah it looks like a Next.js typecheck failed?

#

Someone fixed this issue yesterday by adding downlevelIteration to their convex/tsconfig.json, but there's something we'll need to figure out here.

haughty tusk
#

Ok, will try and get back to you.

runic cove
#

Can you share your code for the any issue? Would help to see more examples

haughty tusk
#

Example function with wrapper:

const zMutation = zCustomMutation(mutation, NoOp);

export const applyToOffer = zMutation({
  args: { data: applicationValidator },
  handler: withUser(async (ctx, args) => {
    const { projectId } = args.data;

    const project = await ctx.db.get(projectId);

    if (!project) {
      throw new ConvexError({
        message: "Project not found",
        code: "INTERNAL_SERVER_ERROR",
        statusCode: 500,
        severity: "error",
      });
    }

    await ctx.db.insert("applications", {
      ...args.data,
      status: "PENDING",
    });
  }),
});
export const applicationValidator = z.object({
  applicantId: zid("users"),
  projectId: zid("projects"),
  offerId: zid("offers"),
  status: applicationStatusValidator,
  position: z.string().max(MAX_OFFER_POSITION_INPUT_LENGTH),
  message: z.string().max(MAX_APPLICATION_MESSAGE_INPUT_LENGTH),
  resume: z.string(),
  skills: z.array(z.string()),
  experience: z.string(),
  updatedAt: z.string(),
});
#

The withUser is copied from fast5 repo:

import { QueryCtx, MutationCtx, mutation, query } from '../_generated/server';
import { Doc } from '../_generated/dataModel';

/**
 * Wrapper for a Convex query or mutation function that provides a user in ctx.
 *
 * Throws an exception if there isn't a user logged in.
 * Pass this to `query`, `mutation`, or another wrapper. E.g.:
 * export default mutation({
 *   handler: withUser(async ({ db, auth, user }, {args}) => {...})
 * });
 * @param func - Your function that can now take in a `user` in the first param.
 * @returns A function to be passed to `query` or `mutation`.
 */
export const withUser = <Ctx extends QueryCtx, Args extends [any] | [], Output>(
  func: (ctx: Ctx & { user: Doc<'users'> }, ...args: Args) => Promise<Output>
): ((ctx: Ctx, ...args: Args) => Promise<Output>) => {
  return async (ctx: Ctx, ...args: Args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) {
      throw new Error(
        'Unauthenticated call to function requiring authentication'
      );
    }
    // Note: If you don't want to define an index right away, you can use
    // db.query("users")
    //  .filter(q => q.eq(q.field("tokenIdentifier"), identity.tokenIdentifier))
    //  .unique();
    const user = await ctx.db
      .query('users')
      .withIndex('by_token', (q) =>
        q.eq('tokenIdentifier', identity.tokenIdentifier)
      )
      .unique();
    if (!user) throw new Error('User not found');
    return func({ ...ctx, user }, ...args);
  };
};
#

Build with the downlevelIteration as true is still failing:

my convex/tsconfig.ts

{
  "compilerOptions": {
    /* These settings are not required by Convex and can be modified. */
    "allowJs": true,
    "strict": false,
    "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",
    "downlevelIteration": true,
    "noEmit": true,

    "isolatedModules": true
  },
  "include": ["./**/*"],
  "exclude": ["_generated"]
}
#

My next.js version is 14.2.7 and node 22.13.1

haughty tusk
#

So I updated dependencies and cleared cache and the problem is no longer appearing but the args still have type any

export const applyToOffer = zMutation({
  args: { data: applicationValidator },
  handler: withUser(async (ctx, args) => {
    const userId = await getAuthUserId(ctx);

    const { projectId } = args.data;

    const project = await ctx.db.get(projectId);

    if (!project) {
      throw new ConvexError({
        message: "Project not found",
        code: "INTERNAL_SERVER_ERROR",
        statusCode: 500,
        severity: "error",
      });
    }

    await ctx.db.insert("applications", {
      ...args.data,
      status: "PENDING",
      applicantId: userId,
    });
  }),
});
runic cove
#

@haughty tusk sorry, I should have been more specific. Could you share all the code, as a GitHub repo? Often the problem is not just with one file, it's an any in another file that causes a propagation of any types via the schema or api object types.

#

We'll see an any coming from somewhere if we look through all the files

haughty tusk
#

Sure, I can share the code, but not publicly. Let me know how you'd like to proceed—DM with link or adding you to a private repo?

runic cove
#

Sure, you can add me, GitHub handle is thomasballinger. I'l write up my method to add it to the docs

#

feel free to email tom@convex.dev

#

or support@convex.dev

haughty tusk
#

ok i will add you in a sec

#

I've sent an invite

runic cove
#

@haughty tusk what file do you see this issue in?

#

I don't see a gameId

haughty tusk
#

convex/PROJECT_FUNCTIONS/applications.ts

the gameId was an example that this happends even if i do it on the 1:1 example from fast5 repo

runic cove
#

I can't find one tha'ts a problem, what's a line where you see an issue?

#

what package manager do you use, I see yarn.lock and a package-lock.json

haughty tusk
#

line 16

#

I use yarn

runic cove
#

tried with yarn too, same thing

#

hm do you have missing dependnecies, what version of TypeScript are you using?

#

you want to track down where an any is coming from, perhaps from an import

#

you might want to use strict mode in TypeScript

#

strict mode highlights anys much more

haughty tusk
#

I see that you are showing the userId type which is fine with displaying but i am talking about any in handler: withUser(async (ctx, args) => - args are type any

runic cove
#

what line number?

haughty tusk
runic cove
#

You might not have pushed recently, I don't see any withUser

haughty tusk
#

I forgot to say that this is on dev branch, sorry

runic cove
#

ah ok I see it now

#

your zod validator seems convertible

#

so nothing's sticking out yet

#

I'll get back to think in a few min

runic cove
#

so the zod stuff is fine without withUser

#

@haughty tusk you said you copied this fancy withUser thing from Fast5? That's pretty old code

#

last updated 2 years ago

haughty tusk
#

Ok i will recreate the withUser using custom functions and see if this will work

runic cove
#

all of this got rewritten when we added argument validators

#

I think that's what you're running into

#

another option is not doing this, and writing a helper function that you use like const currentUser = await getCurrentUser(ctx)

#

but since it's just code, you can get fancy with it if you want, that's what custom functions are

#

but the TypeScript is pretty fancy, personally I prefer calling helper functions

haughty tusk
#

ok, i see. I will try with custom functions, i think this will work perfectly. Thanks for help and getting through my messy code 😄

runic cove
#

I think there might be another version of custom functions specifically for the zod thingyou're doing

#

ah it's called zCustomFunction

haughty tusk
runic cove
#

something like this