fix: replace any types with proper types across codebase

Replace ~100 `any` usages with proper types: use existing interfaces
(RecipeModelType, BriefRecipeType, IPayment, etc.), Record<string, unknown>
for dynamic objects, unknown for catch clauses with proper narrowing,
and inline types for callbacks. Remaining `any` types are in Svelte
components and cases where mongoose document mutation requires casts.
This commit is contained in:
2026-03-02 20:14:51 +01:00
parent b83d793f61
commit 19e46b2b3a
37 changed files with 236 additions and 146 deletions
+6 -4
View File
@@ -1,10 +1,12 @@
import type { RequestHandler } from '@sveltejs/kit';
import { PaymentSplit } from '$models/PaymentSplit';
import { Payment } from '$models/Payment';
import type { IPayment } from '$models/Payment';
import { dbConnect } from '$utils/db';
import { error, json } from '@sveltejs/kit';
import cache from '$lib/server/cache';
type PopulatedPayment = IPayment & { _id: import('mongoose').Types.ObjectId };
interface DebtSummary {
username: string;
netAmount: number; // positive = you owe them, negative = they owe you
@@ -42,7 +44,7 @@ export const GET: RequestHandler = async ({ locals }) => {
.lean();
// Get all other users who have splits with payments involving the current user
const paymentIds = userSplits.map(split => (split.paymentId as any)._id);
const paymentIds = userSplits.map(split => (split.paymentId as unknown as PopulatedPayment)._id);
const allRelatedSplits = await PaymentSplit.find({
paymentId: { $in: paymentIds },
username: { $ne: currentUser }
@@ -55,12 +57,12 @@ export const GET: RequestHandler = async ({ locals }) => {
// Process current user's splits to understand what they owe/are owed
for (const split of userSplits) {
const payment = split.paymentId as any;
const payment = split.paymentId as unknown as PopulatedPayment;
if (!payment) continue;
// Find other participants in this payment
const otherSplits = allRelatedSplits.filter(s =>
(s.paymentId as any)._id.toString() === (split.paymentId as any)._id.toString()
(s.paymentId as unknown as PopulatedPayment)._id.toString() === payment._id.toString()
);
for (const otherSplit of otherSplits) {
@@ -76,7 +76,7 @@ export const GET: RequestHandler = async ({ url, locals }) => {
}
];
const results = await Payment.aggregate(pipeline as any);
const results = await Payment.aggregate(pipeline);
// Transform data into chart-friendly format
const monthsMap = new Map();
@@ -91,7 +91,7 @@ export const GET: RequestHandler = async ({ url, locals }) => {
}
// Populate data
results.forEach((result: any) => {
results.forEach((result: { _id: { yearMonth: string; category: string }; totalAmount: number }) => {
const { yearMonth, category } = result._id;
const amount = result.totalAmount;
@@ -112,7 +112,7 @@ export const GET: RequestHandler = async ({ url, locals }) => {
let firstMonthWithData = 0;
for (let i = 0; i < allMonths.length; i++) {
const monthData = monthsMap.get(allMonths[i]);
const hasData = Object.values(monthData).some((value: any) => value > 0);
const hasData = Object.values(monthData).some((value) => (value as number) > 0);
if (hasData) {
firstMonthWithData = i;
break;
+11 -4
View File
@@ -6,6 +6,13 @@ import { convertToCHF, isValidCurrencyCode } from '$lib/utils/currency';
import { error, json } from '@sveltejs/kit';
import cache, { invalidateCospendCaches } from '$lib/server/cache';
interface SplitInput {
username: string;
amount: number;
proportion?: number;
personalAmount?: number;
}
export const GET: RequestHandler = async ({ locals, url }) => {
const auth = await locals.auth();
if (!auth || !auth.user?.nickname) {
@@ -79,7 +86,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
// Validate personal + equal split method
if (splitMethod === 'personal_equal' && splits) {
const totalPersonal = splits.reduce((sum: number, split: any) => {
const totalPersonal = splits.reduce((sum: number, split: SplitInput) => {
return sum + (parseFloat(split.personalAmount) || 0);
}, 0);
@@ -125,7 +132,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
});
// Convert split amounts to CHF if needed
const convertedSplits = splits.map((split: any) => {
const convertedSplits = splits.map((split: SplitInput) => {
let convertedAmount = split.amount;
let convertedPersonalAmount = split.personalAmount;
@@ -146,14 +153,14 @@ export const POST: RequestHandler = async ({ request, locals }) => {
};
});
const splitPromises = convertedSplits.map((split: any) => {
const splitPromises = convertedSplits.map((split: { paymentId: unknown; username: string; amount: number; proportion?: number; personalAmount?: number }) => {
return PaymentSplit.create(split);
});
await Promise.all(splitPromises);
// Invalidate caches for all affected users
const affectedUsernames = splits.map((split: any) => split.username);
const affectedUsernames = splits.map((split: SplitInput) => split.username);
await invalidateCospendCaches(affectedUsernames, payment._id.toString());
return json({
@@ -36,8 +36,8 @@ export const GET: RequestHandler = async ({ params, locals }) => {
await cache.set(cacheKey, JSON.stringify(result), 1800);
return json(result);
} catch (e: any) {
if (e.status === 404) throw e;
} catch (e: unknown) {
if (e && typeof e === 'object' && 'status' in e && (e as { status: number }).status === 404) throw e;
throw error(500, 'Failed to fetch payment');
} finally {
// Connection will be reused
@@ -89,7 +89,7 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
if (data.splits) {
await PaymentSplit.deleteMany({ paymentId: id });
const splitPromises = data.splits.map((split: any) => {
const splitPromises = data.splits.map((split: { username: string; amount: number; proportion?: number; personalAmount?: number }) => {
return PaymentSplit.create({
paymentId: id,
username: split.username,
@@ -100,7 +100,7 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
});
await Promise.all(splitPromises);
newUsernames = data.splits.map((split: any) => split.username);
newUsernames = data.splits.map((split: { username: string }) => split.username);
}
// Invalidate caches for all users (old and new)
@@ -108,8 +108,8 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
await invalidateCospendCaches(allAffectedUsers, id);
return json({ success: true, payment: updatedPayment });
} catch (e: any) {
if (e.status) throw e;
} catch (e: unknown) {
if (e && typeof e === 'object' && 'status' in e) throw e;
throw error(500, 'Failed to update payment');
} finally {
// Connection will be reused
@@ -148,8 +148,8 @@ export const DELETE: RequestHandler = async ({ params, locals }) => {
await invalidateCospendCaches(affectedUsernames, id);
return json({ success: true });
} catch (e: any) {
if (e.status) throw e;
} catch (e: unknown) {
if (e && typeof e === 'object' && 'status' in e) throw e;
throw error(500, 'Failed to delete payment');
} finally {
// Connection will be reused
@@ -1,5 +1,5 @@
import type { RequestHandler } from '@sveltejs/kit';
import { RecurringPayment } from '$models/RecurringPayment';
import { RecurringPayment, type IRecurringPayment } from '$models/RecurringPayment';
import { dbConnect } from '$utils/db';
import { error, json } from '@sveltejs/kit';
import { calculateNextExecutionDate, validateCronExpression } from '$lib/utils/recurring';
@@ -17,7 +17,7 @@ export const GET: RequestHandler = async ({ locals, url }) => {
await dbConnect();
try {
const query: any = {};
const query: Record<string, unknown> = {};
if (activeOnly) {
query.isActive = true;
}
@@ -86,7 +86,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
// Validate personal + equal split method
if (splitMethod === 'personal_equal' && splits) {
const totalPersonal = splits.reduce((sum: number, split: any) => {
const totalPersonal = splits.reduce((sum: number, split: { personalAmount?: number }) => {
return sum + (parseFloat(split.personalAmount) || 0);
}, 0);
@@ -121,7 +121,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
...recurringPaymentData,
frequency,
cronExpression
} as any, recurringPaymentData.startDate);
} as IRecurringPayment, recurringPaymentData.startDate);
const recurringPayment = await RecurringPayment.create(recurringPaymentData);
@@ -69,7 +69,7 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
throw error(404, 'Recurring payment not found');
}
const updateData: any = {};
const updateData: Record<string, unknown> = {};
if (title !== undefined) updateData.title = title;
if (description !== undefined) updateData.description = description;
@@ -113,7 +113,7 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
// Validate personal + equal split method
if (splitMethod === 'personal_equal' && splits && amount) {
const totalPersonal = splits.reduce((sum: number, split: any) => {
const totalPersonal = splits.reduce((sum: number, split: { personalAmount?: number }) => {
return sum + (parseFloat(split.personalAmount) || 0);
}, 0);
+2 -2
View File
@@ -55,8 +55,8 @@ export const POST: RequestHandler = async ({ request, locals }) => {
path: publicPath
});
} catch (err: any) {
if (err.status) throw err;
} catch (err: unknown) {
if (err && typeof err === 'object' && 'status' in err) throw err;
console.error('Upload error:', err);
throw error(500, 'Failed to upload file');
}