From 378325342341b4a22a006f20b984629e914b3eca Mon Sep 17 00:00:00 2001 From: Matiss Janis Aboltins Date: Mon, 11 Dec 2023 19:55:22 +0000 Subject: [PATCH 1/4] :recycle: (TypeScript) fix strictFunctionTypes violations (pt 1) --- .../src/server/budget/types/handlers.d.ts | 44 ++++++++++++++----- packages/loot-core/src/server/mutators.ts | 5 +-- packages/loot-core/src/server/undo.ts | 17 +++---- packages/loot-core/src/shared/async.ts | 14 +++--- .../loot-core/src/types/api-handlers.d.ts | 4 +- packages/loot-core/src/types/handlers.d.ts | 2 + .../loot-core/src/types/server-handlers.d.ts | 2 +- tsconfig.json | 2 + 8 files changed, 54 insertions(+), 36 deletions(-) diff --git a/packages/loot-core/src/server/budget/types/handlers.d.ts b/packages/loot-core/src/server/budget/types/handlers.d.ts index bb3f6964080..66c2f72c731 100644 --- a/packages/loot-core/src/server/budget/types/handlers.d.ts +++ b/packages/loot-core/src/server/budget/types/handlers.d.ts @@ -5,13 +5,13 @@ export interface BudgetHandlers { category: string /* category id */; month: string; amount: number; - }) => Promise; + }) => Promise; - 'budget/copy-previous-month': (...args: unknown[]) => Promise; + 'budget/copy-previous-month': (arg: { month: string }) => Promise; - 'budget/set-zero': (...args: unknown[]) => Promise; + 'budget/set-zero': (arg: { month: string }) => Promise; - 'budget/set-3month-avg': (...args: unknown[]) => Promise; + 'budget/set-3month-avg': (arg: { month: string }) => Promise; 'budget/check-templates': () => Promise; @@ -27,17 +27,37 @@ export interface BudgetHandlers { month: string; }) => Promise; - 'budget/hold-for-next-month': (...args: unknown[]) => Promise; + 'budget/hold-for-next-month': (arg: { + month: string; + amount: number; + }) => Promise; - 'budget/reset-hold': (...args: unknown[]) => Promise; + 'budget/reset-hold': (arg: { month: string }) => Promise; - 'budget/cover-overspending': (...args: unknown[]) => Promise; + 'budget/cover-overspending': (arg: { + month: string; + to: string; + from: string; + }) => Promise; - 'budget/transfer-available': (...args: unknown[]) => Promise; + 'budget/transfer-available': (arg: { + month: string; + amount: number; + category: string; + }) => Promise; - 'budget/transfer-category': (...args: unknown[]) => Promise; + 'budget/transfer-category': (arg: { + month: string; + amount: number; + to: string; + from: string; + }) => Promise; - 'budget/set-carryover': (...args: unknown[]) => Promise; + 'budget/set-carryover': (arg: { + startMonth: string; + category: string; + flag: boolean; + }) => Promise; 'budget/apply-single-template': (arg: { month: string; @@ -48,10 +68,10 @@ export interface BudgetHandlers { month: string; N: number; category: string; //category id - }) => Promise; + }) => Promise; 'budget/copy-single-month': (arg: { month: string; category: string; //category id - }) => Promise; + }) => Promise; } diff --git a/packages/loot-core/src/server/mutators.ts b/packages/loot-core/src/server/mutators.ts index 9d85c086157..3988e5c58f8 100644 --- a/packages/loot-core/src/server/mutators.ts +++ b/packages/loot-core/src/server/mutators.ts @@ -1,5 +1,6 @@ import { captureException, captureBreadcrumb } from '../platform/exceptions'; import { sequential } from '../shared/async'; +import { type HandlerFunctions } from '../types/handlers'; const runningMethods = new Set(); @@ -9,9 +10,7 @@ let globalMutationsEnabled = false; let _latestHandlerNames = []; -export function mutator unknown>( - handler: T, -): T { +export function mutator(handler: T): T { mutatingMethods.set(handler, true); return handler; } diff --git a/packages/loot-core/src/server/undo.ts b/packages/loot-core/src/server/undo.ts index faf5fa9278d..549c6a8ca61 100644 --- a/packages/loot-core/src/server/undo.ts +++ b/packages/loot-core/src/server/undo.ts @@ -2,6 +2,7 @@ import { Timestamp } from '@actual-app/crdt'; import * as connection from '../platform/server/connection'; import { getIn } from '../shared/util'; +import { type HandlerFunctions } from '../types/handlers'; import { withMutatorContext, getMutatorContext } from './mutators'; import { Message, sendMessages } from './sync'; @@ -89,18 +90,10 @@ export function withUndo( ); } -// for some reason `void` is not inferred properly without this overload -export function undoable( - func: (...args: Args) => Promise, -): (...args: Args) => Promise; -export function undoable< - Args extends unknown[], - Return extends Promise, ->(func: (...args: Args) => Return): (...args: Args) => Return; -export function undoable(func: (...args: unknown[]) => Promise) { - return (...args: unknown[]) => { - return withUndo(() => { - return func(...args); +export function undoable(func: T) { + return (...args: Parameters) => { + return withUndo>>(() => { + return func.apply(null, ...args); }); }; } diff --git a/packages/loot-core/src/shared/async.ts b/packages/loot-core/src/shared/async.ts index 718204f3663..0e6a0c92200 100644 --- a/packages/loot-core/src/shared/async.ts +++ b/packages/loot-core/src/shared/async.ts @@ -1,4 +1,6 @@ -export function sequential unknown>( +import { type HandlerFunctions } from '../types/handlers'; + +export function sequential( fn: T, ): (...args: Parameters) => Promise>> { const sequenceState = { @@ -16,7 +18,7 @@ export function sequential unknown>( } function run(args, resolve, reject) { - sequenceState.running = fn(...args); + sequenceState.running = fn.apply(null, args); sequenceState.running.then( val => { @@ -43,13 +45,13 @@ export function sequential unknown>( }; } -export function once Promise>( +export function once( fn: T, ): (...args: Parameters) => Promise>> { let promise = null; - const onceFn = (...args: Parameters): Promise>> => { + return (...args) => { if (!promise) { - promise = fn(...args).finally(() => { + promise = fn.apply(null, args).finally(() => { promise = null; }); return promise; @@ -57,6 +59,4 @@ export function once Promise>( return promise; }; - - return onceFn; } diff --git a/packages/loot-core/src/types/api-handlers.d.ts b/packages/loot-core/src/types/api-handlers.d.ts index 30e7b5b66bc..71bc1530666 100644 --- a/packages/loot-core/src/types/api-handlers.d.ts +++ b/packages/loot-core/src/types/api-handlers.d.ts @@ -1,3 +1,5 @@ +import { type ServerHandlers } from './server-handlers'; + export interface ApiHandlers { 'api/batch-budget-start': () => Promise; @@ -5,7 +7,7 @@ export interface ApiHandlers { 'api/load-budget': ( ...args: Parameters - ) => Promise; + ) => Promise; 'api/download-budget': (arg: { syncId; password }) => Promise; diff --git a/packages/loot-core/src/types/handlers.d.ts b/packages/loot-core/src/types/handlers.d.ts index 2537c027962..7d131d44554 100644 --- a/packages/loot-core/src/types/handlers.d.ts +++ b/packages/loot-core/src/types/handlers.d.ts @@ -17,3 +17,5 @@ export interface Handlers RulesHandlers, SchedulesHandlers, ToolsHandlers {} + +export type HandlerFunctions = Handlers[keyof Handlers]; diff --git a/packages/loot-core/src/types/server-handlers.d.ts b/packages/loot-core/src/types/server-handlers.d.ts index 9553f836363..59d7f8d26ad 100644 --- a/packages/loot-core/src/types/server-handlers.d.ts +++ b/packages/loot-core/src/types/server-handlers.d.ts @@ -321,7 +321,7 @@ export interface ServerHandlers { error?: { message: string; reason: string; meta: unknown }; }>; - 'load-budget': (arg: { id }) => Promise<{ error }>; + 'load-budget': (arg: { id: string }) => Promise<{ error }>; 'create-demo-budget': () => Promise; diff --git a/tsconfig.json b/tsconfig.json index 1a4dce7bf8f..844bcaf11c4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,8 @@ "downlevelIteration": true, // TODO: enable once every file is ts // "strict": true, + // TODO: enable once the violations are fixed + // "strictFunctionTypes": true, "noFallthroughCasesInSwitch": true, "skipLibCheck": true, "jsx": "preserve", From f039130435c4ee86173bda95e4bc73e1d46af816 Mon Sep 17 00:00:00 2001 From: Matiss Janis Aboltins Date: Mon, 11 Dec 2023 19:56:42 +0000 Subject: [PATCH 2/4] Release notes --- upcoming-release-notes/2065.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 upcoming-release-notes/2065.md diff --git a/upcoming-release-notes/2065.md b/upcoming-release-notes/2065.md new file mode 100644 index 00000000000..873d58604ec --- /dev/null +++ b/upcoming-release-notes/2065.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +Fixing TypeScript issues when enabling `strictFunctionTypes`. From 56bef95a45b8b0603b25e249a8dbf3da521f8221 Mon Sep 17 00:00:00 2001 From: Matiss Janis Aboltins Date: Mon, 11 Dec 2023 20:01:44 +0000 Subject: [PATCH 3/4] oops --- packages/loot-core/src/server/undo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/loot-core/src/server/undo.ts b/packages/loot-core/src/server/undo.ts index 549c6a8ca61..ac12e9c388c 100644 --- a/packages/loot-core/src/server/undo.ts +++ b/packages/loot-core/src/server/undo.ts @@ -93,7 +93,7 @@ export function withUndo( export function undoable(func: T) { return (...args: Parameters) => { return withUndo>>(() => { - return func.apply(null, ...args); + return func.apply(null, args); }); }; } From 670788696888b1189d208600496e838a25614706 Mon Sep 17 00:00:00 2001 From: Matiss Janis Aboltins Date: Mon, 11 Dec 2023 20:26:36 +0000 Subject: [PATCH 4/4] :recycle: (TypeScript) fix strictFunctionTypes violations (pt 2) --- .../desktop-client/src/components/sidebar/Item.tsx | 4 +++- .../src/components/sidebar/SecondaryItem.tsx | 4 +++- packages/desktop-client/src/components/sort.tsx | 10 +++++++--- packages/desktop-client/src/components/table.tsx | 2 +- packages/loot-core/package.json | 2 +- .../loot-core/src/server/sync/sync.property.test.ts | 6 +++--- upcoming-release-notes/2066.md | 6 ++++++ yarn.lock | 10 +++++----- 8 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 upcoming-release-notes/2066.md diff --git a/packages/desktop-client/src/components/sidebar/Item.tsx b/packages/desktop-client/src/components/sidebar/Item.tsx index 32ec1c87ef6..043e44d4123 100644 --- a/packages/desktop-client/src/components/sidebar/Item.tsx +++ b/packages/desktop-client/src/components/sidebar/Item.tsx @@ -13,7 +13,9 @@ import ItemContent from './ItemContent'; type ItemProps = { title: string; - Icon: ComponentType>; + Icon: + | ComponentType> + | ComponentType>; to?: string; children?: ReactNode; style?: CSSProperties; diff --git a/packages/desktop-client/src/components/sidebar/SecondaryItem.tsx b/packages/desktop-client/src/components/sidebar/SecondaryItem.tsx index dbe355c35e7..0780acbfb4e 100644 --- a/packages/desktop-client/src/components/sidebar/SecondaryItem.tsx +++ b/packages/desktop-client/src/components/sidebar/SecondaryItem.tsx @@ -16,7 +16,9 @@ const fontWeight = 600; type SecondaryItemProps = { title: string; to?: string; - Icon?: ComponentType>; + Icon?: + | ComponentType> + | ComponentType>; style?: CSSProperties; onClick?: MouseEventHandler; bold?: boolean; diff --git a/packages/desktop-client/src/components/sort.tsx b/packages/desktop-client/src/components/sort.tsx index 10e7d963d11..a3ce6cb883c 100644 --- a/packages/desktop-client/src/components/sort.tsx +++ b/packages/desktop-client/src/components/sort.tsx @@ -72,7 +72,7 @@ export function useDraggable({ } export type OnDropCallback = ( - id: unknown, + id: string, dropPos: DropPosition, targetId: unknown, ) => Promise | void; @@ -86,7 +86,7 @@ type UseDroppableArgs = { onLongHover?: OnLongHoverCallback; }; -export function useDroppable({ +export function useDroppable({ types, id, onDrop, @@ -95,7 +95,11 @@ export function useDroppable({ const ref = useRef(null); const [dropPos, setDropPos] = useState(null); - const [{ isOver }, dropRef] = useDrop({ + const [{ isOver }, dropRef] = useDrop< + { item: T }, + unknown, + { isOver: boolean } + >({ accept: types, drop({ item }) { onDrop(item.id, dropPos, id); diff --git a/packages/desktop-client/src/components/table.tsx b/packages/desktop-client/src/components/table.tsx index b85928335f1..92e2e833a47 100644 --- a/packages/desktop-client/src/components/table.tsx +++ b/packages/desktop-client/src/components/table.tsx @@ -660,7 +660,7 @@ export function SelectCell({ type SheetCellValueProps = { binding: Binding; type: string; - getValueStyle?: (value: unknown) => CSSProperties; + getValueStyle?: (value: string | number) => CSSProperties; formatExpr?: (value) => string; unformatExpr?: (value: string) => unknown; privacyFilter?: ConditionalPrivacyFilterProps['privacyFilter']; diff --git a/packages/loot-core/package.json b/packages/loot-core/package.json index 44c8460f753..d6c155b264f 100644 --- a/packages/loot-core/package.json +++ b/packages/loot-core/package.json @@ -46,7 +46,7 @@ "@swc/core": "^1.3.82", "@swc/helpers": "^0.5.1", "@swc/jest": "^0.2.29", - "@types/better-sqlite3": "^7.6.7", + "@types/better-sqlite3": "^7.6.8", "@types/jest": "^27.5.0", "@types/jlongster__sql.js": "npm:@types/sql.js@latest", "@types/pegjs": "^0.10.3", diff --git a/packages/loot-core/src/server/sync/sync.property.test.ts b/packages/loot-core/src/server/sync/sync.property.test.ts index 9532405d486..346eb3f16ce 100644 --- a/packages/loot-core/src/server/sync/sync.property.test.ts +++ b/packages/loot-core/src/server/sync/sync.property.test.ts @@ -93,7 +93,7 @@ const baseTime = 1565374471903; const clientId1 = '80dd7da215247293'; const clientId2 = '90xU1sd5124329ac'; -function makeGen({ +function makeGen>({ table, row, field, @@ -102,7 +102,7 @@ function makeGen({ table: string; row?: Arbitrary; field: string; - value: Arbitrary; + value: T; }) { return jsc.record({ dataset: jsc.constant(table), @@ -127,7 +127,7 @@ function makeGen({ }); } -const generators = []; +const generators: Array> = []; Object.keys(schema).forEach(table => { Object.keys(schema[table]).reduce((obj, field) => { if (table === 'spreadsheet_cells' && field === 'expr') { diff --git a/upcoming-release-notes/2066.md b/upcoming-release-notes/2066.md new file mode 100644 index 00000000000..6ff11102d47 --- /dev/null +++ b/upcoming-release-notes/2066.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +Fixing TypeScript issues when enabling `strictFunctionTypes` (pt.2). diff --git a/yarn.lock b/yarn.lock index 2251b1091e1..19999972fb6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4300,12 +4300,12 @@ __metadata: languageName: node linkType: hard -"@types/better-sqlite3@npm:^7.6.7": - version: 7.6.7 - resolution: "@types/better-sqlite3@npm:7.6.7" +"@types/better-sqlite3@npm:^7.6.8": + version: 7.6.8 + resolution: "@types/better-sqlite3@npm:7.6.8" dependencies: "@types/node": "npm:*" - checksum: 5021c1bae4a494408c1a77d84bc31dc15e373b8a1cf8880acba6517f63bc5c2dbf032c81938641346fb967600dbebc1475033c2458b5a5b93eb8f2c53bdbcbf8 + checksum: 404e9b7210564866b0f8878353cc6a16c6ffb313077cbb5aec6176ad2b0a30f64236f03f0a40d36d86bf4eab7658bdcd6d6a8a65dc377de7910fc9e9932885a4 languageName: node linkType: hard @@ -13385,7 +13385,7 @@ __metadata: "@swc/helpers": "npm:^0.5.1" "@swc/jest": "npm:^0.2.29" "@types/adm-zip": "npm:^0.5.0" - "@types/better-sqlite3": "npm:^7.6.7" + "@types/better-sqlite3": "npm:^7.6.8" "@types/jest": "npm:^27.5.0" "@types/jlongster__sql.js": "npm:@types/sql.js@latest" "@types/pegjs": "npm:^0.10.3"