diff --git a/packages/loot-core/src/shared/async.ts b/packages/loot-core/src/shared/async.ts index 0e6a0c92200..847bfeabfab 100644 --- a/packages/loot-core/src/shared/async.ts +++ b/packages/loot-core/src/shared/async.ts @@ -3,24 +3,25 @@ import { type HandlerFunctions } from '../types/handlers'; export function sequential( fn: T, ): (...args: Parameters) => Promise>> { - const sequenceState = { + const sequenceState: { + running: Promise>> | null; + queue: Array<{ args: Parameters; resolve; reject }>; + } = { running: null, queue: [], }; function pump() { - if (sequenceState.queue.length > 0) { - const next = sequenceState.queue.shift(); + const next = sequenceState.queue.shift(); + if (next !== undefined) { run(next.args, next.resolve, next.reject); } else { sequenceState.running = null; } } - function run(args, resolve, reject) { - sequenceState.running = fn.apply(null, args); - - sequenceState.running.then( + function run(args: Parameters, resolve, reject) { + sequenceState.running = fn.apply(null, args).then( val => { pump(); resolve(val); @@ -47,9 +48,9 @@ export function sequential( export function once( fn: T, -): (...args: Parameters) => Promise>> { - let promise = null; - return (...args) => { +): (...args: Parameters) => Promise>> | null { + let promise: Promise>> | null = null; + return (...args: Parameters) => { if (!promise) { promise = fn.apply(null, args).finally(() => { promise = null; diff --git a/packages/loot-core/src/shared/months.ts b/packages/loot-core/src/shared/months.ts index d314391a825..09e6a4ba280 100644 --- a/packages/loot-core/src/shared/months.ts +++ b/packages/loot-core/src/shared/months.ts @@ -182,7 +182,7 @@ export function _range( end: DateLike, inclusive = false, ): string[] { - const months = []; + const months: string[] = []; let month = monthFromDate(start); while (d.isBefore(_parse(month), _parse(end))) { months.push(month); @@ -209,15 +209,15 @@ export function _dayRange( end: DateLike, inclusive = false, ): string[] { - const days = []; + const days: string[] = []; let day = start; while (d.isBefore(_parse(day), _parse(end))) { - days.push(day); + days.push(dayFromDate(day)); day = addDays(day, 1); } if (inclusive) { - days.push(day); + days.push(dayFromDate(day)); } return days; diff --git a/packages/loot-core/src/shared/query.ts b/packages/loot-core/src/shared/query.ts index 1bd35e101d2..5905bed35cf 100644 --- a/packages/loot-core/src/shared/query.ts +++ b/packages/loot-core/src/shared/query.ts @@ -1,5 +1,5 @@ export type QueryState = { - filterExpressions: Array; + filterExpressions: Array; selectExpressions: Array; groupExpressions: Array; orderExpressions: Array; diff --git a/packages/loot-core/src/shared/schedules.ts b/packages/loot-core/src/shared/schedules.ts index 52d2e0092dd..ed53f380d17 100644 --- a/packages/loot-core/src/shared/schedules.ts +++ b/packages/loot-core/src/shared/schedules.ts @@ -3,7 +3,11 @@ import type { IRuleOptions } from '@rschedule/core'; import * as monthUtils from './months'; import { q } from './query'; -export function getStatus(nextDate, completed, hasTrans) { +export function getStatus( + nextDate: string, + completed: boolean, + hasTrans: boolean, +) { const today = monthUtils.currentDay(); if (completed) { @@ -44,7 +48,7 @@ export function getHasTransactionsQuery(schedules) { .select(['schedule', 'date']); } -function makeNumberSuffix(num) { +function makeNumberSuffix(num: number) { // Slight abuse of date-fns to turn a number like "1" into the full // form "1st" but formatting a date with that number return monthUtils.format(new Date(2020, 0, num, 12), 'do'); @@ -127,7 +131,7 @@ export function getRecurringDescription(config, dateFormat) { desc += ' on the '; - const strs = []; + const strs: string[] = []; const uniqueDays = new Set(patterns.map(p => p.type)); const isSameDay = uniqueDays.size === 1 && !uniqueDays.has('day'); diff --git a/packages/loot-core/src/shared/test-helpers.ts b/packages/loot-core/src/shared/test-helpers.ts index 5cda8013519..5b62338d8c5 100644 --- a/packages/loot-core/src/shared/test-helpers.ts +++ b/packages/loot-core/src/shared/test-helpers.ts @@ -1,6 +1,6 @@ -export let tracer = null; +export let tracer: null | ReturnType = null; -function timeout(promise, n) { +function timeout>(promise: T, n: number) { let resolve; const timeoutPromise = new Promise(_ => (resolve = _)); const timer = setTimeout(() => resolve(`timeout(${n})`), n); @@ -18,16 +18,20 @@ export function resetTracer() { tracer = execTracer(); } -export function execTracer() { - const queue = []; +export function execTracer() { + const queue: Array<{ name: string; data?: T }> = []; let hasStarted = false; - let waitingFor = null; + let waitingFor: null | { + name: string; + reject: (error: Error) => void; + resolve: (data?: T) => void; + } = null; let ended = false; const log = false; return { - event(name: string, data?: unknown) { + event(name: string, data?: T) { if (!hasStarted) { return; } else if (log) { @@ -56,7 +60,7 @@ export function execTracer() { } }, - wait(name) { + wait(name: string) { if (waitingFor) { throw new Error( `Already waiting for ${waitingFor.name}, cannot wait for multiple events`, @@ -68,48 +72,40 @@ export function execTracer() { }); }, - expectWait(name, data) { + expectWait(name: string, data?: T) { if (!hasStarted) { throw new Error(`Expected “${name}” but tracer hasn’t started yet`); } else if (log) { console.log(`--- expectWait(${name}) ---`); } - let promise = this.wait(name); + const promise = this.wait(name); if (data === undefined) { // We want to ignore the result - promise = promise.then(() => true); - data = true; + return; } - if (typeof data === 'function') { - return expect(timeout(promise, 1000)) - .resolves.toBeTruthy() - .then(() => promise) - .then(res => data(res)); - } else { - // We use this form because it tracks the right location in the - // test when it fails. It's annoying to always write this in the - // test though, so this provides a clean API. The right line - // number in the test will show up in the stack. - return expect(timeout(promise, 1000)).resolves.toEqual(data); - } + // We use this form because it tracks the right location in the + // test when it fails. It's annoying to always write this in the + // test though, so this provides a clean API. The right line + // number in the test will show up in the stack. + return expect(timeout(promise, 1000)).resolves.toEqual(data); }, - expectNow(name, data) { + expectNow(name: string, data?: T) { if (!hasStarted) { throw new Error(`Expected “${name}” but tracer hasn’t started yet`); } else if (log) { console.log(`--- expectNow(${name}) ---`); } - if (queue.length === 0) { + const entry = queue.shift(); + + if (!entry) { throw new Error( `Expected event “${name}” but none found - has it happened yet?`, ); - } else if (queue[0].name === name) { - const entry = queue.shift(); - + } else if (entry.name === name) { if (typeof data === 'function') { data(entry.data); } else { @@ -122,7 +118,7 @@ export function execTracer() { } }, - expect(name: string, data?: unknown) { + expect(name: string, data?: T) { if (queue.length === 0) { return this.expectWait(name, data); } diff --git a/upcoming-release-notes/2228.md b/upcoming-release-notes/2228.md new file mode 100644 index 00000000000..e12eb6fb1f7 --- /dev/null +++ b/upcoming-release-notes/2228.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +TypeScript: fix some `strictNullChecks: true` issues (pt.2)