diff --git a/packages/loot-core/src/client/accounts/accountsSlice.ts b/packages/loot-core/src/client/accounts/accountsSlice.ts index 535cbb6c10..6c8ce6b718 100644 --- a/packages/loot-core/src/client/accounts/accountsSlice.ts +++ b/packages/loot-core/src/client/accounts/accountsSlice.ts @@ -194,7 +194,7 @@ function handleSyncResponse( } type SyncAccountsPayload = { - id?: AccountEntity['id']; + id?: AccountEntity['id'] | undefined; }; export const syncAccounts = createAppAsyncThunk( diff --git a/packages/loot-core/src/client/actions/budgets.ts b/packages/loot-core/src/client/actions/budgets.ts index fa4ee860e8..e07febef25 100644 --- a/packages/loot-core/src/client/actions/budgets.ts +++ b/packages/loot-core/src/client/actions/budgets.ts @@ -168,8 +168,8 @@ export function duplicateBudget({ loadBudget = 'none', cloudSync, }: { - id?: string; - cloudId?: string; + id?: string | undefined; + cloudId?: string | undefined; oldName: string; newName: string; managePage?: boolean; @@ -178,7 +178,7 @@ export function duplicateBudget({ * cloudSync is used to determine if the duplicate budget * should be synced to the server */ - cloudSync?: boolean; + cloudSync: boolean; }) { return async (dispatch: AppDispatch) => { try { diff --git a/packages/loot-core/src/client/data-hooks/reports.ts b/packages/loot-core/src/client/data-hooks/reports.ts index d10acfe659..53a4614c44 100644 --- a/packages/loot-core/src/client/data-hooks/reports.ts +++ b/packages/loot-core/src/client/data-hooks/reports.ts @@ -27,9 +27,9 @@ function toJS(rows: CustomReportData[]) { includeCurrentInterval: row.include_current === 1, showUncategorized: row.show_uncategorized === 1, graphType: row.graph_type, - conditions: row.conditions, + ...(row.conditions && { conditions: row.conditions }), conditionsOp: row.conditions_op ?? 'and', - data: row.metadata, + ...(row.metadata && { metadata: row.metadata }), }; return report; }); diff --git a/packages/loot-core/src/client/data-hooks/transactions.ts b/packages/loot-core/src/client/data-hooks/transactions.ts index 4bf415e816..4711766c19 100644 --- a/packages/loot-core/src/client/data-hooks/transactions.ts +++ b/packages/loot-core/src/client/data-hooks/transactions.ts @@ -91,7 +91,9 @@ export function useTransactions({ } }, onError, - options: { pageCount: optionsRef.current.pageCount }, + options: optionsRef.current.pageCount + ? { pageCount: optionsRef.current.pageCount } + : {}, }); return () => { @@ -122,7 +124,7 @@ export function useTransactions({ return { transactions, isLoading, - error, + ...(error && { error }), reload, loadMore, isLoadingMore, @@ -274,10 +276,11 @@ export function usePreviewTransactions(): UsePreviewTransactionsResult { }; }, [scheduleTransactions, schedules, statuses, upcomingLength]); + const returnError = error || scheduleQueryError; return { data: previewTransactions, isLoading: isLoading || isSchedulesLoading, - error: error || scheduleQueryError, + ...(returnError && { error: returnError }), }; } diff --git a/packages/loot-core/src/client/query-hooks.ts b/packages/loot-core/src/client/query-hooks.ts index e5ea7449dc..02a66e412d 100644 --- a/packages/loot-core/src/client/query-hooks.ts +++ b/packages/loot-core/src/client/query-hooks.ts @@ -53,6 +53,6 @@ export function useQuery( return { data, isLoading, - error, + ...(error && { error }), }; } diff --git a/packages/loot-core/src/client/state-types/modals.d.ts b/packages/loot-core/src/client/state-types/modals.d.ts index ceab1d7c49..d2140d43cd 100644 --- a/packages/loot-core/src/client/state-types/modals.d.ts +++ b/packages/loot-core/src/client/state-types/modals.d.ts @@ -42,7 +42,7 @@ type FinanceModals = { 'select-linked-accounts': { accounts: unknown[]; requisitionId?: string; - upgradingAccountId?: string; + upgradingAccountId?: string | undefined; syncSource?: AccountSyncSource; }; @@ -74,7 +74,7 @@ type FinanceModals = { onMoveExternal: (arg: { institutionId: string; }) => Promise<{ error: string } | { data: unknown }>; - onClose?: () => void; + onClose?: (() => void) | undefined; onSuccess: (data: GoCardlessToken) => Promise; }; diff --git a/packages/loot-core/src/client/state-types/notifications.d.ts b/packages/loot-core/src/client/state-types/notifications.d.ts index cebb60b8eb..52423e6867 100644 --- a/packages/loot-core/src/client/state-types/notifications.d.ts +++ b/packages/loot-core/src/client/state-types/notifications.d.ts @@ -1,21 +1,23 @@ import type * as constants from '../constants'; export type Notification = { - id?: string; + id?: string | undefined; // 'warning' is unhandled?? type?: 'message' | 'error' | 'warning'; - pre?: string; - title?: string; + pre?: string | undefined; + title?: string | undefined; message: string; - sticky?: boolean; - timeout?: number; - button?: { - title: string; - action: () => void | Promise; - }; - messageActions?: Record void>; - onClose?: () => void; - internal?: string; + sticky?: boolean | undefined; + timeout?: number | undefined; + button?: + | { + title: string; + action: () => void | Promise; + } + | undefined; + messageActions?: Record void> | undefined; + onClose?: (() => void) | undefined; + internal?: string | undefined; }; type NotificationWithId = Notification & { id: string }; diff --git a/packages/loot-core/src/mocks/index.ts b/packages/loot-core/src/mocks/index.ts index 92a8a4194b..82005d2918 100644 --- a/packages/loot-core/src/mocks/index.ts +++ b/packages/loot-core/src/mocks/index.ts @@ -98,9 +98,13 @@ export function generateCategoryGroups( return definition.map(group => { const g = generateCategoryGroup(group.name ?? '', group.is_income); + if (!group.categories) { + return g; + } + return { ...g, - categories: group.categories?.map(cat => + categories: group.categories.map(cat => generateCategory(cat.name, g.id, cat.is_income), ), }; @@ -117,9 +121,9 @@ function _generateTransaction( notes: 'Notes', account: data.account, date: data.date || monthUtils.currentDay(), - category: data.category, sort_order: data.sort_order != null ? data.sort_order : 1, cleared: false, + ...(data.category && { category: data.category }), }; } @@ -186,7 +190,7 @@ export function generateTransactions( { account: accountId, category: groupId, - amount: isSplit ? 50 : undefined, + ...(isSplit && { amount: 50 }), sort_order: i, }, isSplit ? 30 : undefined, diff --git a/packages/loot-core/src/server/api-models.ts b/packages/loot-core/src/server/api-models.ts index b6923bcc83..7285f93ef9 100644 --- a/packages/loot-core/src/server/api-models.ts +++ b/packages/loot-core/src/server/api-models.ts @@ -54,7 +54,7 @@ export const categoryModel = { name: category.name, is_income: category.is_income ? true : false, hidden: category.hidden ? true : false, - group_id: category.cat_group, + ...(category.cat_group && { group_id: category.cat_group }), }; }, diff --git a/packages/loot-core/src/server/errors.ts b/packages/loot-core/src/server/errors.ts index 09be2e9f62..e218c13c15 100644 --- a/packages/loot-core/src/server/errors.ts +++ b/packages/loot-core/src/server/errors.ts @@ -1,6 +1,6 @@ // TODO: normalize error types export class PostError extends Error { - meta?: { meta: string }; + meta: { meta: string } | undefined; reason: string; type: 'PostError'; @@ -24,14 +24,15 @@ export class HTTPError extends Error { } export class SyncError extends Error { - meta?: + meta: | { isMissingKey: boolean; } | { error: { message: string; stack: string }; query: { sql: string; params: Array }; - }; + } + | undefined; reason: string; constructor( diff --git a/packages/loot-core/src/shared/test-helpers.ts b/packages/loot-core/src/shared/test-helpers.ts index fbdf98896e..320e7bfe84 100644 --- a/packages/loot-core/src/shared/test-helpers.ts +++ b/packages/loot-core/src/shared/test-helpers.ts @@ -19,7 +19,7 @@ export function resetTracer() { } export function execTracer() { - const queue: Array<{ name: string; data?: T }> = []; + const queue: Array<{ name: string; data?: T | undefined }> = []; let hasStarted = false; let waitingFor: null | { name: string; diff --git a/packages/loot-core/src/shared/transactions.ts b/packages/loot-core/src/shared/transactions.ts index 1e0bc97eb8..6142640bce 100644 --- a/packages/loot-core/src/shared/transactions.ts +++ b/packages/loot-core/src/shared/transactions.ts @@ -249,9 +249,12 @@ export function updateTransaction( let child = t; if (trans.id === transaction.id) { + const { payee: childPayee, ...rest } = t; + const newPayee = + childPayee === trans.payee ? transaction.payee : childPayee; child = { - ...t, - payee: t.payee === trans.payee ? transaction.payee : t.payee, + ...rest, + ...(newPayee != null ? { payee: newPayee } : {}), }; } else if (t.id === transaction.id) { child = transaction; @@ -260,7 +263,10 @@ export function updateTransaction( return makeChild(parent, child); }); - return recalculateSplit({ ...parent, subtransactions: sub }); + return recalculateSplit({ + ...parent, + ...(sub && { subtransactions: sub }), + }); } else { return transaction; } @@ -283,7 +289,10 @@ export function deleteTransaction( } satisfies TransactionEntity; } else { const sub = trans.subtransactions?.filter(t => t.id !== id); - return recalculateSplit({ ...trans, subtransactions: sub }); + return recalculateSplit({ + ...trans, + ...(sub && { subtransactions: sub }), + }); } } else { return null; diff --git a/packages/loot-core/src/types/server-handlers.d.ts b/packages/loot-core/src/types/server-handlers.d.ts index 7cc0ebb3c5..71dd1ec9cb 100644 --- a/packages/loot-core/src/types/server-handlers.d.ts +++ b/packages/loot-core/src/types/server-handlers.d.ts @@ -192,7 +192,7 @@ export interface ServerHandlers { 'secret-check': (arg: string) => Promise; 'gocardless-poll-web-token': (arg: { - upgradingAccountId?: string; + upgradingAccountId?: string | undefined; requisitionId: string; }) => Promise< { error: 'unknown' } | { error: 'timeout' } | { data: GoCardlessToken } @@ -228,7 +228,7 @@ export interface ServerHandlers { 'gocardless-poll-web-token-stop': () => Promise<'ok'>; 'gocardless-create-web-token': (arg: { - upgradingAccountId?: string; + upgradingAccountId?: string | undefined; institutionId: string; accessValidForDays: number; }) => Promise< @@ -385,8 +385,8 @@ export interface ServerHandlers { 'close-budget': () => Promise<'ok'>; 'delete-budget': (arg: { - id?: string; - cloudFileId?: string; + id?: string | undefined; + cloudFileId?: string | undefined; }) => Promise<'ok' | 'fail'>; /** @@ -399,8 +399,8 @@ export interface ServerHandlers { * @returns {Promise} The ID of the newly created budget. */ 'duplicate-budget': (arg: { - id?: string; - cloudId?: string; + id?: string | undefined; + cloudId?: string | undefined; newName: string; cloudSync?: boolean; open: 'none' | 'original' | 'copy'; diff --git a/upcoming-release-notes/4214.md b/upcoming-release-notes/4214.md new file mode 100644 index 0000000000..78b903c9e2 --- /dev/null +++ b/upcoming-release-notes/4214.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [jfdoming] +--- + +Make `loot-core` compatible with `exactOptionalPropertyTypes`