AlphaOmega
AlphaOmega3w ago

TS2589: Type instantiation is excessively deep and possibly infinite.

Getting this when calling internal and api like here
await ctx.runMutation(internal.services.parkingSpot.createMany, {
data: spots.map((parkingSpot) => ({
categories: parkingSpot.categories,
parkingLot: parkingLotId,
})),
});
await ctx.runMutation(internal.services.parkingSpot.createMany, {
data: spots.map((parkingSpot) => ({
categories: parkingSpot.categories,
parkingLot: parkingLotId,
})),
});
What can I do?
No description
7 Replies
lee
lee3w ago
Actions | Convex Developer Hub
Actions can call third party services to do things such as processing a payment
AlphaOmega
AlphaOmegaOP3w ago
It's a different issue, this is about type complexity and I dont get it on the return value, that's actually correct, i get it on the internal or api import itself would me typing out the returns validator on each function fix this?
erquhart
erquhart3w ago
It's still likely the same issue, shows up in different places. I've seen this happen across all my convex function references in some situations, due to one ctx.runQuery(). Look at your recently touched usages of ctx.runQuery/Mutation/Action to figure out where it's happening.
AlphaOmega
AlphaOmegaOP2w ago
Ok ill look into where i mightve called them That didnt fix it, i typed out all my run calls ( not a lot btw ) and typed out the returns of every function in my model directory Here is an example
export const getMyParkingLots = withAuthenticatedQueryContext(
async (ctx): Promise<ParkingLot.ParkingLotPreview[]> => {
const parkingLots = await ParkingLot.getByUser(ctx, {
userId: ctx.user._id,
});

return pruneNull(
await Promise.all(
parkingLots.map(({ _id }) =>
ParkingLot.getPreviewById(ctx, { id: _id })
)
)
);
}
);
export const getMyParkingLots = withAuthenticatedQueryContext(
async (ctx): Promise<ParkingLot.ParkingLotPreview[]> => {
const parkingLots = await ParkingLot.getByUser(ctx, {
userId: ctx.user._id,
});

return pruneNull(
await Promise.all(
parkingLots.map(({ _id }) =>
ParkingLot.getPreviewById(ctx, { id: _id })
)
)
);
}
);
export const getMyParkingLots = authenticatedQuery({
args: {},
handler: Provider.getMyParkingLots,
});
export const getMyParkingLots = authenticatedQuery({
args: {},
handler: Provider.getMyParkingLots,
});
every function in my project is like this, every call to ctx.run_ whose returns is used
export const book = withAuthenticatedActionContext(
async (
ctx,
{
parkingLotId,
vehicleId,
slot,
}: {
parkingLotId: Id<"parkingLots">;
vehicleId: Id<"vehicles">;
slot: Slot;
}
): Promise<{ booking: Booking; paymentIntent: Payment.PaymentIntent }> => {
const ongoingBookings: Doc<"bookings">[] = await ctx.runQuery(
internal.services.booking.getOngoing,
{
userId: ctx.user._id,
}
);

const conflictsWithRequestedSlot = hasConflict(ongoingBookings, slot);

if (conflictsWithRequestedSlot) {
throw new ConvexError(BookingError.ACTIVE_BOOKING_EXISTS);
}
export const book = withAuthenticatedActionContext(
async (
ctx,
{
parkingLotId,
vehicleId,
slot,
}: {
parkingLotId: Id<"parkingLots">;
vehicleId: Id<"vehicles">;
slot: Slot;
}
): Promise<{ booking: Booking; paymentIntent: Payment.PaymentIntent }> => {
const ongoingBookings: Doc<"bookings">[] = await ctx.runQuery(
internal.services.booking.getOngoing,
{
userId: ctx.user._id,
}
);

const conflictsWithRequestedSlot = hasConflict(ongoingBookings, slot);

if (conflictsWithRequestedSlot) {
throw new ConvexError(BookingError.ACTIVE_BOOKING_EXISTS);
}
is explicitly typed, and yet, when using internal or api i get the type instantiation error
erquhart
erquhart2w ago
Your handler return type annotations can't utilize Convex generated types, otherwise you're back in the same boat. Do ParkingLot, Booking, and/or Payment use types that utilize schema or anything from convex/_generated?
AlphaOmega
AlphaOmegaOP2w ago
Yes they utilize Doc I can remove that dependency, not ideal though
erquhart
erquhart2w ago
It's often easier to pinpoint something closer to the actual runQuery/Mutation/Action. Like, maybe after you run the query, you're just returning a small subset of the received value, so you just type those statically in place. That's what I'm doing in all such instances currently. May or may not help in your situation, depending on usage. Ah your last example is doing inline, just noticed that yeah, so for example if you're just getting ongoing bookings to check for conflicts, maybe hasConflict only needs one or two properties from each booking document, I think just typing that subset works
const ongoingBookings: { usedProp: string, otherUsedProp: number }[] = await ctx.runQuery(
internal.services.booking.getOngoing,
{
userId: ctx.user._id,
}
);

const conflictsWithRequestedSlot = hasConflict(ongoingBookings, slot);
const ongoingBookings: { usedProp: string, otherUsedProp: number }[] = await ctx.runQuery(
internal.services.booking.getOngoing,
{
userId: ctx.user._id,
}
);

const conflictsWithRequestedSlot = hasConflict(ongoingBookings, slot);
Taking a minimal typing approach in general is often helpful. Eg., a function that only uses one or two props that are present in a document can just rely on an object with those types rather than requiring the entire object to be satisfied.

Did you find this page helpful?