diff --git a/packages/desktop-client/src/components/reports/reports/CashFlowCard.jsx b/packages/desktop-client/src/components/reports/reports/CashFlowCard.tsx
similarity index 85%
rename from packages/desktop-client/src/components/reports/reports/CashFlowCard.jsx
rename to packages/desktop-client/src/components/reports/reports/CashFlowCard.tsx
index 0c13c2251184052c3522d2e0ae3648bfde54be47..e1aa13f1a9162235071184002e5bfe977af75055 100644
--- a/packages/desktop-client/src/components/reports/reports/CashFlowCard.jsx
+++ b/packages/desktop-client/src/components/reports/reports/CashFlowCard.tsx
@@ -1,4 +1,5 @@
 import React, { useState, useMemo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
 
 import { Bar, BarChart, LabelList, ResponsiveContainer } from 'recharts';
 
@@ -18,15 +19,25 @@ import { ReportCard } from '../ReportCard';
 import { simpleCashFlow } from '../spreadsheets/cash-flow-spreadsheet';
 import { useReport } from '../useReport';
 
+type CustomLabelProps = {
+  value?: number;
+  name: string;
+  position?: 'left' | 'right';
+  x?: number;
+  y?: number;
+  width?: number;
+  height?: number;
+};
+
 function CustomLabel({
-  value,
+  value = 0,
   name,
-  position,
-  x,
-  y,
-  width: barWidth,
-  height: barHeight,
-}) {
+  position = 'left',
+  x = 0,
+  y = 0,
+  width: barWidth = 0,
+  height: barHeight = 0,
+}: CustomLabelProps) {
   const valueLengthOffset = 20;
 
   const yOffset = barHeight < 25 ? 105 : y;
@@ -68,7 +79,13 @@ function CustomLabel({
   );
 }
 
-export function CashFlowCard({ isEditing, onRemove }) {
+type CashFlowCardProps = {
+  isEditing?: boolean;
+  onRemove: () => void;
+};
+
+export function CashFlowCard({ isEditing, onRemove }: CashFlowCardProps) {
+  const { t } = useTranslation();
   const end = monthUtils.currentDay();
   const start = monthUtils.currentMonth() + '-01';
 
@@ -76,8 +93,8 @@ export function CashFlowCard({ isEditing, onRemove }) {
   const data = useReport('cash_flow_simple', params);
 
   const [isCardHovered, setIsCardHovered] = useState(false);
-  const onCardHover = useCallback(() => setIsCardHovered(true));
-  const onCardHoverEnd = useCallback(() => setIsCardHovered(false));
+  const onCardHover = useCallback(() => setIsCardHovered(true), []);
+  const onCardHoverEnd = useCallback(() => setIsCardHovered(false), []);
 
   const { graphData } = data || {};
   const expenses = -(graphData?.expense || 0);
@@ -90,7 +107,7 @@ export function CashFlowCard({ isEditing, onRemove }) {
       menuItems={[
         {
           name: 'remove',
-          text: 'Remove',
+          text: t('Remove'),
         },
       ]}
       onMenuSelect={item => {
@@ -153,7 +170,7 @@ export function CashFlowCard({ isEditing, onRemove }) {
                     <LabelList
                       dataKey="income"
                       position="left"
-                      content={<CustomLabel name="Income" />}
+                      content={<CustomLabel name={t('Income')} />}
                     />
                   </Bar>
 
@@ -165,7 +182,7 @@ export function CashFlowCard({ isEditing, onRemove }) {
                     <LabelList
                       dataKey="expenses"
                       position="right"
-                      content={<CustomLabel name="Expenses" />}
+                      content={<CustomLabel name={t('Expenses')} />}
                     />
                   </Bar>
                 </BarChart>
diff --git a/packages/desktop-client/src/components/reports/reports/NetWorthCard.jsx b/packages/desktop-client/src/components/reports/reports/NetWorthCard.tsx
similarity index 87%
rename from packages/desktop-client/src/components/reports/reports/NetWorthCard.jsx
rename to packages/desktop-client/src/components/reports/reports/NetWorthCard.tsx
index aab03f09920817c04ee5ddb68281446cadf635f5..877312728e7053d2eb4d59e6f752db1dafe2e91c 100644
--- a/packages/desktop-client/src/components/reports/reports/NetWorthCard.jsx
+++ b/packages/desktop-client/src/components/reports/reports/NetWorthCard.tsx
@@ -1,7 +1,9 @@
 import React, { useState, useMemo, useCallback } from 'react';
+import { useTranslation } from 'react-i18next';
 
 import * as monthUtils from 'loot-core/src/shared/months';
 import { integerToCurrency } from 'loot-core/src/shared/util';
+import { type AccountEntity } from 'loot-core/src/types/models';
 
 import { useResponsive } from '../../../ResponsiveProvider';
 import { styles } from '../../../style';
@@ -16,14 +18,25 @@ import { ReportCard } from '../ReportCard';
 import { createSpreadsheet as netWorthSpreadsheet } from '../spreadsheets/net-worth-spreadsheet';
 import { useReport } from '../useReport';
 
-export function NetWorthCard({ isEditing, accounts, onRemove }) {
+type NetWorthCardProps = {
+  isEditing?: boolean;
+  accounts: AccountEntity[];
+  onRemove: () => void;
+};
+
+export function NetWorthCard({
+  isEditing,
+  accounts,
+  onRemove,
+}: NetWorthCardProps) {
+  const { t } = useTranslation();
   const { isNarrowWidth } = useResponsive();
 
   const end = monthUtils.currentMonth();
   const start = monthUtils.subMonths(end, 5);
   const [isCardHovered, setIsCardHovered] = useState(false);
-  const onCardHover = useCallback(() => setIsCardHovered(true));
-  const onCardHoverEnd = useCallback(() => setIsCardHovered(false));
+  const onCardHover = useCallback(() => setIsCardHovered(true), []);
+  const onCardHoverEnd = useCallback(() => setIsCardHovered(false), []);
 
   const params = useMemo(
     () => netWorthSpreadsheet(start, end, accounts),
@@ -38,7 +51,7 @@ export function NetWorthCard({ isEditing, accounts, onRemove }) {
       menuItems={[
         {
           name: 'remove',
-          text: 'Remove',
+          text: t('Remove'),
         },
       ]}
       onMenuSelect={item => {
@@ -88,8 +101,6 @@ export function NetWorthCard({ isEditing, accounts, onRemove }) {
 
         {data ? (
           <NetWorthGraph
-            start={start}
-            end={end}
             graphData={data.graphData}
             compact={true}
             showTooltip={!isEditing && !isNarrowWidth}
diff --git a/packages/desktop-client/src/components/reports/reports/SpendingCard.tsx b/packages/desktop-client/src/components/reports/reports/SpendingCard.tsx
index 9127e3040d2d9ed08acfc838ae6f51e7cf10d549..0f1f01406523bbb6a3f752127957fdb54258d4f7 100644
--- a/packages/desktop-client/src/components/reports/reports/SpendingCard.tsx
+++ b/packages/desktop-client/src/components/reports/reports/SpendingCard.tsx
@@ -1,4 +1,5 @@
 import React, { useState, useMemo } from 'react';
+import { Trans, useTranslation } from 'react-i18next';
 
 import * as monthUtils from 'loot-core/src/shared/months';
 import { amountToCurrency } from 'loot-core/src/shared/util';
@@ -25,6 +26,8 @@ type SpendingCardProps = {
 };
 
 export function SpendingCard({ isEditing, onRemove }: SpendingCardProps) {
+  const { t } = useTranslation();
+
   const [isCardHovered, setIsCardHovered] = useState(false);
   const [spendingReportFilter = ''] = useLocalPref('spendingReportFilter');
   const [spendingReportTime = 'lastMonth'] = useLocalPref('spendingReportTime');
@@ -59,7 +62,9 @@ export function SpendingCard({ isEditing, onRemove }: SpendingCardProps) {
   if (!spendingReportFeatureFlag) {
     return (
       <MissingReportCard isEditing={isEditing} onRemove={onRemove}>
-        The experimental spending report feature has not been enabled.
+        <Trans>
+          The experimental spending report feature has not been enabled.
+        </Trans>
       </MissingReportCard>
     );
   }
@@ -71,7 +76,7 @@ export function SpendingCard({ isEditing, onRemove }: SpendingCardProps) {
       menuItems={[
         {
           name: 'remove',
-          text: 'Remove',
+          text: t('Remove'),
         },
       ]}
       onMenuSelect={item => {
@@ -128,7 +133,7 @@ export function SpendingCard({ isEditing, onRemove }: SpendingCardProps) {
         {!showLastMonth ? (
           <View style={{ padding: 5 }}>
             <p style={{ margin: 0, textAlign: 'center' }}>
-              Additional data required to generate graph
+              <Trans>Additional data required to generate graph</Trans>
             </p>
           </View>
         ) : data ? (
@@ -140,7 +145,7 @@ export function SpendingCard({ isEditing, onRemove }: SpendingCardProps) {
             compare={spendingReportCompare}
           />
         ) : (
-          <LoadingIndicator message="Loading report..." />
+          <LoadingIndicator message={t('Loading report...')} />
         )}
       </View>
     </ReportCard>
diff --git a/packages/desktop-client/src/components/reports/spreadsheets/cash-flow-spreadsheet.tsx b/packages/desktop-client/src/components/reports/spreadsheets/cash-flow-spreadsheet.tsx
index b0ea66d48ed31d979d86af7af88e3f3a9067fbe0..04a7967d09b94ac11dc14799f785b3a40a327d92 100644
--- a/packages/desktop-client/src/components/reports/spreadsheets/cash-flow-spreadsheet.tsx
+++ b/packages/desktop-client/src/components/reports/spreadsheets/cash-flow-spreadsheet.tsx
@@ -1,4 +1,3 @@
-// @ts-strict-ignore
 import React from 'react';
 
 import * as d from 'date-fns';
@@ -13,8 +12,11 @@ import { type RuleConditionEntity } from 'loot-core/types/models';
 import { AlignedText } from '../../common/AlignedText';
 import { runAll, indexCashFlow } from '../util';
 
-export function simpleCashFlow(start, end) {
-  return async (spreadsheet, setData) => {
+export function simpleCashFlow(start: string, end: string) {
+  return async (
+    spreadsheet: ReturnType<typeof useSpreadsheet>,
+    setData: (data: { graphData: { income: number; expense: number } }) => void,
+  ) => {
     function makeQuery() {
       return q('transactions')
         .filter({
@@ -109,7 +111,16 @@ export function cashFlowByDate(
   };
 }
 
-function recalculate(data, start, end, isConcise) {
+function recalculate(
+  data: [
+    number,
+    Array<{ date: string; isTransfer: string | null; amount: number }>,
+    Array<{ date: string; isTransfer: string | null; amount: number }>,
+  ],
+  start: string,
+  end: string,
+  isConcise: boolean,
+) {
   const [startingBalance, income, expense] = data;
   const convIncome = income.map(t => {
     return { ...t, isTransfer: t.isTransfer !== null };
@@ -123,15 +134,25 @@ function recalculate(data, start, end, isConcise) {
         monthUtils.getMonth(end),
       )
     : monthUtils.dayRangeInclusive(start, end);
-  const incomes = indexCashFlow(convIncome, 'date', 'isTransfer');
-  const expenses = indexCashFlow(convExpense, 'date', 'isTransfer');
+  const incomes = indexCashFlow(convIncome);
+  const expenses = indexCashFlow(convExpense);
 
   let balance = startingBalance;
   let totalExpenses = 0;
   let totalIncome = 0;
   let totalTransfers = 0;
 
-  const graphData = dates.reduce(
+  const graphData = dates.reduce<{
+    expenses: Array<{ x: Date; y: number }>;
+    income: Array<{ x: Date; y: number }>;
+    transfers: Array<{ x: Date; y: number }>;
+    balances: Array<{
+      x: Date;
+      y: number;
+      premadeLabel: JSX.Element;
+      amount: number;
+    }>;
+  }>(
     (res, date) => {
       let income = 0;
       let expense = 0;
diff --git a/packages/desktop-client/src/components/reports/spreadsheets/net-worth-spreadsheet.ts b/packages/desktop-client/src/components/reports/spreadsheets/net-worth-spreadsheet.ts
index 2fc4c1ae272ceece19f729659f649801b397ed0f..49c01d96d6c7cf48ff24fa250c47a123928974fb 100644
--- a/packages/desktop-client/src/components/reports/spreadsheets/net-worth-spreadsheet.ts
+++ b/packages/desktop-client/src/components/reports/spreadsheets/net-worth-spreadsheet.ts
@@ -26,7 +26,7 @@ export function createSpreadsheet(
   end: string,
   accounts: AccountEntity[],
   conditions: RuleConditionEntity[] = [],
-  conditionsOp: 'and' | 'or',
+  conditionsOp: 'and' | 'or' = 'and',
 ) {
   return async (
     spreadsheet: ReturnType<typeof useSpreadsheet>,
diff --git a/packages/desktop-client/src/components/reports/util.ts b/packages/desktop-client/src/components/reports/util.ts
index ab45b9bb550ae16011081a77af5be4e809bc2f7b..2495a1c09528c26997d2b37026b041bcc63b83c6 100644
--- a/packages/desktop-client/src/components/reports/util.ts
+++ b/packages/desktop-client/src/components/reports/util.ts
@@ -20,16 +20,12 @@ export async function runAll(
 
 export function indexCashFlow<
   T extends { date: string; isTransfer: boolean; amount: number },
->(data: T[], date: string, isTransfer: string) {
-  const results = {};
+>(data: T[]): Record<string, Record<'true' | 'false', number>> {
+  const results: Record<string, Record<'true' | 'false', number>> = {};
   data.forEach(item => {
-    const findExisting = results[item.date]
-      ? results[item.date][item.isTransfer]
-        ? results[item.date][item.isTransfer]
-        : 0
-      : 0;
-    const result = { [item[isTransfer]]: item.amount + findExisting };
-    results[item[date]] = { ...results[item[date]], ...result };
+    const findExisting = results?.[item.date]?.[String(item.isTransfer)] ?? 0;
+    const result = { [String(item.isTransfer)]: item.amount + findExisting };
+    results[item.date] = { ...results[item.date], ...result };
   });
   return results;
 }
diff --git a/packages/loot-core/src/types/server-handlers.d.ts b/packages/loot-core/src/types/server-handlers.d.ts
index f455b2bbb0eda466b9a2d251d47e7e0e54dbd2ef..51967882f0e59e0d7cf4e30b2112e37d5ddc32b4 100644
--- a/packages/loot-core/src/types/server-handlers.d.ts
+++ b/packages/loot-core/src/types/server-handlers.d.ts
@@ -18,6 +18,7 @@ import {
   PayeeEntity,
 } from './models';
 import { GlobalPrefs, LocalPrefs } from './prefs';
+import { Query } from './query';
 import { EmptyObject } from './util';
 
 export interface ServerHandlers {
@@ -137,7 +138,7 @@ export interface ServerHandlers {
 
   'create-query': (arg: { sheetName; name; query }) => Promise<unknown>;
 
-  query: (query) => Promise<{ data; dependencies }>;
+  query: (query: Query) => Promise<{ data: unknown; dependencies }>;
 
   'account-update': (arg: { id; name }) => Promise<unknown>;
 
diff --git a/upcoming-release-notes/3285.md b/upcoming-release-notes/3285.md
new file mode 100644
index 0000000000000000000000000000000000000000..fa0c39c09978c968a0310d7889def3142b3c796e
--- /dev/null
+++ b/upcoming-release-notes/3285.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [Matissjanis]
+---
+
+TypeScript: migrate report cards to TS.