fix(types): flatten tRPC Zod schema types to resolve TS2589 inference depth errors

Cast Zod schemas with .refine()/.superRefine() to z.ZodType<InferredType> at the
procedure level. This short-circuits TypeScript's deep type recursion through
tRPC's middleware chain, eliminating 4 of 5 @ts-expect-error TS2589 suppressions
in web components (VacationModal, ProjectModal, UsersClient, CountriesClient).

Applied same pattern to allocation, timeline, staffing, dashboard, project, and
resource query/mutation procedures to reduce client-side type depth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 15:28:12 +02:00
parent 0d79f97d7a
commit 9bd3781c03
21 changed files with 460 additions and 304 deletions
@@ -18,17 +18,23 @@ import {
toIsoDate,
} from "./staffing-shared.js";
const SearchCapacityInputSchema = z.object({
startDate: z.coerce.date(),
endDate: z.coerce.date(),
minHoursPerDay: z.number().optional().default(4),
roleName: z.string().optional(),
chapter: z.string().optional(),
limit: z.number().int().min(1).max(100).optional().default(20),
});
export const staffingCapacityReadProcedures = {
searchCapacity: planningReadProcedure
.input(
z.object({
startDate: z.coerce.date(),
endDate: z.coerce.date(),
minHoursPerDay: z.number().optional().default(4),
roleName: z.string().optional(),
chapter: z.string().optional(),
limit: z.number().int().min(1).max(100).optional().default(20),
}),
SearchCapacityInputSchema as z.ZodType<
z.infer<typeof SearchCapacityInputSchema>,
z.ZodTypeDef,
z.input<typeof SearchCapacityInputSchema>
>,
)
.query(async ({ ctx, input }) => {
const where: Record<string, unknown> = { isActive: true };
@@ -107,7 +113,8 @@ export const staffingCapacityReadProcedures = {
});
const bookedHours = (bookingsByResourceId.get(resource.id) ?? []).reduce(
(sum, booking) =>
sum + calculateEffectiveBookedHours({
sum +
calculateEffectiveBookedHours({
availability,
startDate: booking.startDate,
endDate: booking.endDate,
@@ -179,15 +186,17 @@ export const staffingCapacityReadProcedures = {
const availability = resource.availability as unknown as WeekdayAvailability;
const contexts = await loadResourceDailyAvailabilityContexts(
ctx.db,
[{
id: resource.id,
availability,
countryId: resource.countryId,
countryCode: resource.country?.code,
federalState: resource.federalState,
metroCityId: resource.metroCityId,
metroCityName: resource.metroCity?.name,
}],
[
{
id: resource.id,
availability,
countryId: resource.countryId,
countryCode: resource.country?.code,
federalState: resource.federalState,
metroCityId: resource.metroCityId,
metroCityName: resource.metroCity?.name,
},
],
input.startDate,
input.endDate,
);
@@ -231,9 +240,8 @@ export const staffingCapacityReadProcedures = {
cursor.setUTCDate(cursor.getUTCDate() + 1);
}
const currentChargeability = totalAvailableHours > 0
? (totalChargeableHours / totalAvailableHours) * 100
: 0;
const currentChargeability =
totalAvailableHours > 0 ? (totalChargeableHours / totalAvailableHours) * 100 : 0;
return {
resourceId: resource.id,
@@ -291,15 +299,17 @@ export const staffingCapacityReadProcedures = {
const availability = resource.availability as unknown as WeekdayAvailability;
const contexts = await loadResourceDailyAvailabilityContexts(
ctx.db,
[{
id: resource.id,
availability,
countryId: resource.countryId,
countryCode: resource.country?.code,
federalState: resource.federalState,
metroCityId: resource.metroCityId,
metroCityName: resource.metroCity?.name,
}],
[
{
id: resource.id,
availability,
countryId: resource.countryId,
countryCode: resource.country?.code,
federalState: resource.federalState,
metroCityId: resource.metroCityId,
metroCityName: resource.metroCity?.name,
},
],
input.startDate,
input.endDate,
);