From 2f676e87215f51725fbf6d9c6f276513617c40b3 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:41:39 +0200 Subject: [PATCH 01/34] Pass generic parameter to all lottie requires --- src/components/LottieAnimations/index.tsx | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/components/LottieAnimations/index.tsx b/src/components/LottieAnimations/index.tsx index 657fe79b401f..63e31a60a95b 100644 --- a/src/components/LottieAnimations/index.tsx +++ b/src/components/LottieAnimations/index.tsx @@ -1,79 +1,80 @@ +import type {LottieViewProps} from 'lottie-react-native'; import colors from '@styles/theme/colors'; import variables from '@styles/variables'; import type DotLottieAnimation from './types'; const DotLottieAnimations = { Abracadabra: { - file: require('@assets/animations/Abracadabra.lottie'), + file: require('@assets/animations/Abracadabra.lottie'), w: 375, h: 400, }, FastMoney: { - file: require('@assets/animations/FastMoney.lottie'), + file: require('@assets/animations/FastMoney.lottie'), w: 375, h: 240, }, Fireworks: { - file: require('@assets/animations/Fireworks.lottie'), + file: require('@assets/animations/Fireworks.lottie'), w: 360, h: 360, }, Hands: { - file: require('@assets/animations/Hands.lottie'), + file: require('@assets/animations/Hands.lottie'), w: 375, h: 375, }, PreferencesDJ: { - file: require('@assets/animations/PreferencesDJ.lottie'), + file: require('@assets/animations/PreferencesDJ.lottie'), w: 375, h: 240, backgroundColor: colors.blue500, }, ReviewingBankInfo: { - file: require('@assets/animations/ReviewingBankInfo.lottie'), + file: require('@assets/animations/ReviewingBankInfo.lottie'), w: 280, h: 280, }, WorkspacePlanet: { - file: require('@assets/animations/WorkspacePlanet.lottie'), + file: require('@assets/animations/WorkspacePlanet.lottie'), w: 375, h: 240, backgroundColor: colors.pink800, }, SaveTheWorld: { - file: require('@assets/animations/SaveTheWorld.lottie'), + file: require('@assets/animations/SaveTheWorld.lottie'), w: 375, h: 240, }, Safe: { - file: require('@assets/animations/Safe.lottie'), + file: require('@assets/animations/Safe.lottie'), w: 625, h: 400, backgroundColor: colors.ice500, }, Magician: { - file: require('@assets/animations/Magician.lottie'), + file: require('@assets/animations/Magician.lottie'), w: 853, h: 480, }, Update: { - file: require('@assets/animations/Update.lottie'), + file: require('@assets/animations/Update.lottie'), w: variables.updateAnimationW, h: variables.updateAnimationH, }, Coin: { - file: require('@assets/animations/Coin.lottie'), + file: require('@assets/animations/Coin.lottie'), w: 375, h: 240, backgroundColor: colors.yellow600, }, Desk: { - file: require('@assets/animations/Desk.lottie'), + file: require('@assets/animations/Desk.lottie'), w: 200, h: 120, }, Plane: { - file: require('@assets/animations/Plane.lottie'), + file: require('@assets/animations/Plane.lottie'), w: 180, h: 200, }, From c2cbd8efacad81c387151b99cac0cc6b260ba80a Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:41:56 +0200 Subject: [PATCH 02/34] Remove unsafe assigment --- .eslintrc.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index f909258cb0ee..4a3291c86023 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -105,8 +105,6 @@ module.exports = { __DEV__: 'readonly', }, rules: { - '@typescript-eslint/no-unsafe-assignment': 'off', - // TypeScript specific rules '@typescript-eslint/prefer-enum-initializers': 'error', '@typescript-eslint/no-var-requires': 'off', From dd47f88ba81e19840d3af734a2587d17ed11a078 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:42:32 +0200 Subject: [PATCH 03/34] Add asserts to JSON.parse --- .github/actions/javascript/bumpVersion/bumpVersion.ts | 2 +- .../createOrUpdateStagingDeploy.ts | 4 ++-- .../actions/javascript/getGraphiteString/getGraphiteString.ts | 2 +- .../javascript/getPreviousVersion/getPreviousVersion.ts | 2 +- .../validateReassureOutput/validateReassureOutput.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/javascript/bumpVersion/bumpVersion.ts b/.github/actions/javascript/bumpVersion/bumpVersion.ts index eba79c7c9edb..6c0aab1bdb43 100644 --- a/.github/actions/javascript/bumpVersion/bumpVersion.ts +++ b/.github/actions/javascript/bumpVersion/bumpVersion.ts @@ -48,7 +48,7 @@ if (!semanticVersionLevel || !Object.keys(versionUpdater.SEMANTIC_VERSION_LEVELS console.log(`Invalid input for 'SEMVER_LEVEL': ${semanticVersionLevel}`, `Defaulting to: ${semanticVersionLevel}`); } -const {version: previousVersion}: PackageJson = JSON.parse(fs.readFileSync('./package.json').toString()); +const {version: previousVersion} = JSON.parse(fs.readFileSync('./package.json').toString()) as PackageJson; if (!previousVersion) { core.setFailed('Error: Could not read package.json'); } diff --git a/.github/actions/javascript/createOrUpdateStagingDeploy/createOrUpdateStagingDeploy.ts b/.github/actions/javascript/createOrUpdateStagingDeploy/createOrUpdateStagingDeploy.ts index aed8b9dcba0a..caff455e9fa5 100644 --- a/.github/actions/javascript/createOrUpdateStagingDeploy/createOrUpdateStagingDeploy.ts +++ b/.github/actions/javascript/createOrUpdateStagingDeploy/createOrUpdateStagingDeploy.ts @@ -8,13 +8,13 @@ import GitUtils from '@github/libs/GitUtils'; type IssuesCreateResponse = Awaited>['data']; -type PackageJSON = { +type PackageJson = { version: string; }; async function run(): Promise { // Note: require('package.json').version does not work because ncc will resolve that to a plain string at compile time - const packageJson: PackageJSON = JSON.parse(fs.readFileSync('package.json', 'utf8')); + const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8')) as PackageJson; const newVersionTag = packageJson.version; try { diff --git a/.github/actions/javascript/getGraphiteString/getGraphiteString.ts b/.github/actions/javascript/getGraphiteString/getGraphiteString.ts index 5231caa79ed5..93d5d8a9618b 100644 --- a/.github/actions/javascript/getGraphiteString/getGraphiteString.ts +++ b/.github/actions/javascript/getGraphiteString/getGraphiteString.ts @@ -33,7 +33,7 @@ const run = () => { } try { - const current: RegressionEntry = JSON.parse(entry); + const current = JSON.parse(entry) as RegressionEntry; // Extract timestamp, Graphite accepts timestamp in seconds if (current.metadata?.creationDate) { diff --git a/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts b/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts index 262b603124fa..5e8839b72444 100644 --- a/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts +++ b/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts @@ -8,7 +8,7 @@ if (!semverLevel || !Object.values(versionUpdater.SEMANTIC_VERSION_LEVEL core.setFailed(`'Error: Invalid input for 'SEMVER_LEVEL': ${semverLevel}`); } -const {version: currentVersion}: PackageJson = JSON.parse(readFileSync('./package.json', 'utf8')); +const {version: currentVersion} = JSON.parse(readFileSync('./package.json', 'utf8')) as PackageJson; if (!currentVersion) { core.setFailed('Error: Could not read package.json'); } diff --git a/.github/actions/javascript/validateReassureOutput/validateReassureOutput.ts b/.github/actions/javascript/validateReassureOutput/validateReassureOutput.ts index ad0f393a96a2..d843caf61518 100644 --- a/.github/actions/javascript/validateReassureOutput/validateReassureOutput.ts +++ b/.github/actions/javascript/validateReassureOutput/validateReassureOutput.ts @@ -3,7 +3,7 @@ import type {CompareResult, PerformanceEntry} from '@callstack/reassure-compare/ import fs from 'fs'; const run = (): boolean => { - const regressionOutput: CompareResult = JSON.parse(fs.readFileSync('.reassure/output.json', 'utf8')); + const regressionOutput = JSON.parse(fs.readFileSync('.reassure/output.json', 'utf8')) as CompareResult; const countDeviation = Number(core.getInput('COUNT_DEVIATION', {required: true})); const durationDeviation = Number(core.getInput('DURATION_DEVIATION_PERCENTAGE', {required: true})); From 711d0282b2fb2fb7940c1568271dd7ff38c9a50b Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:43:20 +0200 Subject: [PATCH 04/34] Use assertion for @vue/preload-webpack-plugin require --- config/webpack/webpack.common.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/config/webpack/webpack.common.ts b/config/webpack/webpack.common.ts index bedd7e50ef94..33fd9131eca0 100644 --- a/config/webpack/webpack.common.ts +++ b/config/webpack/webpack.common.ts @@ -4,13 +4,13 @@ import dotenv from 'dotenv'; import fs from 'fs'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import path from 'path'; -import type {Compiler, Configuration} from 'webpack'; +import type {Class} from 'type-fest'; +import type {Configuration, WebpackPluginInstance} from 'webpack'; import {DefinePlugin, EnvironmentPlugin, IgnorePlugin, ProvidePlugin} from 'webpack'; import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer'; import CustomVersionFilePlugin from './CustomVersionFilePlugin'; import type Environment from './types'; -// importing anything from @vue/preload-webpack-plugin causes an error type Options = { rel: string; as: string; @@ -18,13 +18,10 @@ type Options = { include: string; }; -type PreloadWebpackPluginClass = { - new (options?: Options): PreloadWebpackPluginClass; - apply: (compiler: Compiler) => void; -}; +type PreloadWebpackPluginClass = Class; -// require is necessary, there are no types for this package and the declaration file can't be seen by the build process which causes an error. -const PreloadWebpackPlugin: PreloadWebpackPluginClass = require('@vue/preload-webpack-plugin'); +// require is necessary, importing anything from @vue/preload-webpack-plugin causes an error +const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin') as PreloadWebpackPluginClass; const includeModules = [ 'react-native-animatable', From 13f8c0f5f71e5bb5a57e04d2bf32691472222fba Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:44:09 +0200 Subject: [PATCH 05/34] Fix some of jest scripts and mocks --- jest/setup.ts | 4 ++-- jest/setupMockFullstoryLib.ts | 2 +- src/libs/__mocks__/Permissions.ts | 3 ++- src/libs/actions/__mocks__/App.ts | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/jest/setup.ts b/jest/setup.ts index f11a8a4ed631..1485d743dba2 100644 --- a/jest/setup.ts +++ b/jest/setup.ts @@ -1,5 +1,6 @@ import '@shopify/flash-list/jestSetup'; import 'react-native-gesture-handler/jestSetup'; +import type * as RNKeyboardController from 'react-native-keyboard-controller'; import mockStorage from 'react-native-onyx/dist/storage/__mocks__'; import 'setimmediate'; import mockFSLibrary from './setupMockFullstoryLib'; @@ -54,5 +55,4 @@ jest.mock('react-native-share', () => ({ default: jest.fn(), })); -// eslint-disable-next-line @typescript-eslint/no-unsafe-return -jest.mock('react-native-keyboard-controller', () => require('react-native-keyboard-controller/jest')); +jest.mock('react-native-keyboard-controller', () => require('react-native-keyboard-controller/jest')); diff --git a/jest/setupMockFullstoryLib.ts b/jest/setupMockFullstoryLib.ts index 9edfccab9441..eae3ea1f51bd 100644 --- a/jest/setupMockFullstoryLib.ts +++ b/jest/setupMockFullstoryLib.ts @@ -15,7 +15,7 @@ export default function mockFSLibrary() { return { FSPage(): FSPageInterface { return { - start: jest.fn(), + start: jest.fn(() => {}), }; }, default: Fullstory, diff --git a/src/libs/__mocks__/Permissions.ts b/src/libs/__mocks__/Permissions.ts index 634626a507af..702aec6a7bd4 100644 --- a/src/libs/__mocks__/Permissions.ts +++ b/src/libs/__mocks__/Permissions.ts @@ -1,3 +1,4 @@ +import type Permissions from '@libs/Permissions'; import CONST from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; @@ -9,7 +10,7 @@ import type Beta from '@src/types/onyx/Beta'; */ export default { - ...jest.requireActual('../Permissions'), + ...jest.requireActual('../Permissions'), canUseDefaultRooms: (betas: Beta[]) => betas.includes(CONST.BETAS.DEFAULT_ROOMS), canUseViolations: (betas: Beta[]) => betas.includes(CONST.BETAS.VIOLATIONS), }; diff --git a/src/libs/actions/__mocks__/App.ts b/src/libs/actions/__mocks__/App.ts index 3d2b5814684b..4e812b31e3a3 100644 --- a/src/libs/actions/__mocks__/App.ts +++ b/src/libs/actions/__mocks__/App.ts @@ -5,7 +5,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {OnyxUpdatesFromServer} from '@src/types/onyx'; import createProxyForObject from '@src/utils/createProxyForObject'; -const AppImplementation: typeof AppImport = jest.requireActual('@libs/actions/App'); +const AppImplementation = jest.requireActual('@libs/actions/App'); const { setLocale, setLocaleAndNavigate, @@ -40,7 +40,7 @@ const mockValues: AppMockValues = { }; const mockValuesProxy = createProxyForObject(mockValues); -const ApplyUpdatesImplementation: typeof ApplyUpdatesImport = jest.requireActual('@libs/actions/OnyxUpdateManager/utils/applyUpdates'); +const ApplyUpdatesImplementation = jest.requireActual('@libs/actions/OnyxUpdateManager/utils/applyUpdates'); const getMissingOnyxUpdates = jest.fn((_fromID: number, toID: number) => { if (mockValuesProxy.missingOnyxUpdatesToBeApplied === undefined) { return Onyx.set(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, toID); From a7ab17344958e9eb0fcf93f0251562eea18daec3 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:45:04 +0200 Subject: [PATCH 06/34] Add assertion to Console module --- src/libs/Console/index.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/Console/index.ts b/src/libs/Console/index.ts index f03d33674bde..9bbdb173e61b 100644 --- a/src/libs/Console/index.ts +++ b/src/libs/Console/index.ts @@ -87,8 +87,7 @@ const charMap: Record = { * @param text the text to sanitize * @returns the sanitized text */ -function sanitizeConsoleInput(text: string) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-return +function sanitizeConsoleInput(text: string): string { return text.replace(charsToSanitize, (match) => charMap[match]); } @@ -102,7 +101,7 @@ function createLog(text: string) { try { // @ts-expect-error Any code inside `sanitizedInput` that gets evaluated by `eval()` will be executed in the context of the current this value. // eslint-disable-next-line no-eval, no-invalid-this - const result = eval.call(this, text); + const result = eval.call(this, text) as unknown; if (result !== undefined) { return [ @@ -131,7 +130,7 @@ function parseStringifiedMessages(logs: Log[]): Log[] { return logs.map((log) => { try { - const parsedMessage = JSON.parse(log.message); + const parsedMessage = JSON.parse(log.message) as Log['message']; return { ...log, message: parsedMessage, From 7fa04b473272729da598a4f29fe6f4e4cdbb9cc7 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:45:40 +0200 Subject: [PATCH 07/34] Add assertions to yaml parser --- workflow_tests/utils/JobMocker.ts | 4 +--- workflow_tests/utils/preGenerateTest.ts | 2 +- workflow_tests/utils/utils.ts | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/workflow_tests/utils/JobMocker.ts b/workflow_tests/utils/JobMocker.ts index 78be5c5861e6..9434b52ef0a5 100644 --- a/workflow_tests/utils/JobMocker.ts +++ b/workflow_tests/utils/JobMocker.ts @@ -94,9 +94,7 @@ class JobMocker { } readWorkflowFile(location: PathOrFileDescriptor): YamlWorkflow { - const test: YamlWorkflow = yaml.parse(fs.readFileSync(location, 'utf8')); - - return test; + return yaml.parse(fs.readFileSync(location, 'utf8')) as YamlWorkflow; } writeWorkflowFile(location: PathOrFileDescriptor, data: YamlWorkflow) { diff --git a/workflow_tests/utils/preGenerateTest.ts b/workflow_tests/utils/preGenerateTest.ts index 1fbbd6e3de4c..2c2e18eaeafa 100644 --- a/workflow_tests/utils/preGenerateTest.ts +++ b/workflow_tests/utils/preGenerateTest.ts @@ -275,7 +275,7 @@ checkIfMocksFileExists(workflowTestMocksDirectory, workflowTestMocksFileName); const workflowTestAssertionsFileName = `${workflowName}Assertions.ts`; checkIfAssertionsFileExists(workflowTestAssertionsDirectory, workflowTestAssertionsFileName); -const workflow: YamlWorkflow = yaml.parse(fs.readFileSync(workflowFilePath, 'utf8')); +const workflow = yaml.parse(fs.readFileSync(workflowFilePath, 'utf8')) as YamlWorkflow; const workflowJobs = parseWorkflowFile(workflow); const mockFileContent = getMockFileContent(workflowName, workflowJobs); diff --git a/workflow_tests/utils/utils.ts b/workflow_tests/utils/utils.ts index 494f830fb744..1fd60e3f92bc 100644 --- a/workflow_tests/utils/utils.ts +++ b/workflow_tests/utils/utils.ts @@ -170,7 +170,7 @@ function setJobRunners(act: ExtendedAct, jobs: Record, workflowP return act; } - const workflow: Workflow = yaml.parse(fs.readFileSync(workflowPath, 'utf8')); + const workflow = yaml.parse(fs.readFileSync(workflowPath, 'utf8')) as Workflow; Object.entries(jobs).forEach(([jobId, runner]) => { const job = workflow.jobs[jobId]; job['runs-on'] = runner; From 680070a54cb35403a944f00080d2c2fe0499f82b Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:46:00 +0200 Subject: [PATCH 08/34] Change assertion from any to a random actionName --- tests/utils/collections/reportActions.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/utils/collections/reportActions.ts b/tests/utils/collections/reportActions.ts index dc3e9d8427b5..b078420230f5 100644 --- a/tests/utils/collections/reportActions.ts +++ b/tests/utils/collections/reportActions.ts @@ -5,7 +5,7 @@ import type {ReportAction} from '@src/types/onyx'; import type {ActionName} from '@src/types/onyx/OriginalMessage'; import type DeepRecord from '@src/types/utils/DeepRecord'; -const flattenActionNamesValues = (actionNames: DeepRecord) => { +const flattenActionNamesValues = (actionNames: DeepRecord): ActionName[] => { let result: ActionName[] = []; Object.values(actionNames).forEach((value) => { if (typeof value === 'object') { @@ -35,9 +35,10 @@ const deprecatedReportActions: ActionName[] = [ export default function createRandomReportAction(index: number): ReportAction { return { - // we need to add any here because of the way we are generating random values - // eslint-disable-next-line @typescript-eslint/no-explicit-any - actionName: rand(flattenActionNamesValues(CONST.REPORT.ACTIONS.TYPE).filter((actionType: ActionName) => !deprecatedReportActions.includes(actionType))) as any, + // We need to assert the type of actionName so that rest of the properties are inferred correctly + actionName: rand( + flattenActionNamesValues(CONST.REPORT.ACTIONS.TYPE).filter((actionType: ActionName) => !deprecatedReportActions.includes(actionType)), + ) as typeof CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, reportActionID: index.toString(), previousReportActionID: (index === 0 ? 0 : index - 1).toString(), actorAccountID: index, From af0beb84d1cb32ed94f4a53d9b04355f1120f44b Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:46:22 +0200 Subject: [PATCH 09/34] Add type to Electron download event listener --- desktop/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/main.ts b/desktop/main.ts index 6ab0bc6579d7..cb541ca87279 100644 --- a/desktop/main.ts +++ b/desktop/main.ts @@ -617,7 +617,7 @@ const mainWindow = (): Promise => { }); const downloadQueue = createDownloadQueue(); - ipcMain.on(ELECTRON_EVENTS.DOWNLOAD, (event, downloadData) => { + ipcMain.on(ELECTRON_EVENTS.DOWNLOAD, (event, downloadData: DownloadItem) => { const downloadItem: DownloadItem = { ...downloadData, win: browserWindow, From 1c1b9c4c42706750ee977e0358d6310c886ed9ad Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:47:11 +0200 Subject: [PATCH 10/34] Remove unnecessary eslint no-unsafe-return comments --- src/components/FlatList/index.tsx | 1 - src/libs/Navigation/linkingConfig/index.ts | 1 - src/styles/utils/index.ts | 61 +++++++--------------- 3 files changed, 19 insertions(+), 44 deletions(-) diff --git a/src/components/FlatList/index.tsx b/src/components/FlatList/index.tsx index 9f42e9597c79..31909ae0e32d 100644 --- a/src/components/FlatList/index.tsx +++ b/src/components/FlatList/index.tsx @@ -52,7 +52,6 @@ function MVCPFlatList({maintainVisibleContentPosition, horizontal = false return horizontal ? getScrollableNode(scrollRef.current)?.scrollLeft ?? 0 : getScrollableNode(scrollRef.current)?.scrollTop ?? 0; }, [horizontal]); - // eslint-disable-next-line @typescript-eslint/no-unsafe-return const getContentView = useCallback(() => getScrollableNode(scrollRef.current)?.childNodes[0], []); const scrollToOffset = useCallback( diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 64a40a224495..1f556aa67809 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -12,7 +12,6 @@ const linkingConfig: LinkingOptions = { const {adaptedState} = getAdaptedStateFromPath(...args); // ResultState | undefined is the type this function expect. - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return adaptedState; }, subscribe, diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index 44c40e17d60e..c3db1ee40865 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1232,16 +1232,12 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ */ getAutoGrowHeightInputStyle: (textInputHeight: number, maxHeight: number): ViewStyle => { if (textInputHeight > maxHeight) { - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return { ...styles.pr0, ...styles.overflowAuto, }; } - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return { ...styles.pr0, ...styles.overflowHidden, @@ -1270,17 +1266,11 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ getBadgeColorStyle: (isSuccess: boolean, isError: boolean, isPressed = false, isAdHoc = false): ViewStyle => { if (isSuccess) { if (isAdHoc) { - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return isPressed ? styles.badgeAdHocSuccessPressed : styles.badgeAdHocSuccess; } - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return isPressed ? styles.badgeSuccessPressed : styles.badgeSuccess; } if (isError) { - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return isPressed ? styles.badgeDangerPressed : styles.badgeDanger; } return {}; @@ -1357,8 +1347,6 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ ...styles.cursorDisabled, }; - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return { ...styles.link, ...(isDisabled ? disabledLinkStyles : {}), @@ -1424,8 +1412,6 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ getGoogleListViewStyle: (shouldDisplayBorder: boolean): ViewStyle => { if (shouldDisplayBorder) { - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return { ...styles.borderTopRounded, ...styles.borderBottomRounded, @@ -1491,35 +1477,29 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ /** * Generate the wrapper styles for the mini ReportActionContextMenu. */ - getMiniReportActionContextMenuWrapperStyle: (isReportActionItemGrouped: boolean): ViewStyle => - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - ({ - ...(isReportActionItemGrouped ? positioning.tn8 : positioning.tn4), - ...positioning.r4, - ...styles.cursorDefault, - ...styles.userSelectNone, - overflowAnchor: 'none', - position: 'absolute', - zIndex: 8, - }), + getMiniReportActionContextMenuWrapperStyle: (isReportActionItemGrouped: boolean): ViewStyle => ({ + ...(isReportActionItemGrouped ? positioning.tn8 : positioning.tn4), + ...positioning.r4, + ...styles.cursorDefault, + ...styles.userSelectNone, + overflowAnchor: 'none', + position: 'absolute', + zIndex: 8, + }), /** * Generate the styles for the ReportActionItem wrapper view. */ - getReportActionItemStyle: (isHovered = false, isClickable = false): ViewStyle => - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - ({ - display: 'flex', - justifyContent: 'space-between', - backgroundColor: isHovered - ? theme.hoverComponentBG - : // Warning: Setting this to a non-transparent color will cause unread indicator to break on Android - theme.transparent, - opacity: 1, - ...(isClickable ? styles.cursorPointer : styles.cursorInitial), - }), + getReportActionItemStyle: (isHovered = false, isClickable = false): ViewStyle => ({ + display: 'flex', + justifyContent: 'space-between', + backgroundColor: isHovered + ? theme.hoverComponentBG + : // Warning: Setting this to a non-transparent color will cause unread indicator to break on Android + theme.transparent, + opacity: 1, + ...(isClickable ? styles.cursorPointer : styles.cursorInitial), + }), /** * Determines the theme color for a modal based on the app's background color, @@ -1543,12 +1523,9 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ getZoomCursorStyle: (isZoomed: boolean, isDragging: boolean): ViewStyle => { if (!isZoomed) { - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return styles.cursorZoomIn; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return isDragging ? styles.cursorGrabbing : styles.cursorZoomOut; }, From cc84252a480d09a1b003a1fc29c24a7de0decec0 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:48:12 +0200 Subject: [PATCH 11/34] Fix jest.requireActual usage --- .../utils/__mocks__/index.ts | 2 +- tests/actions/OnyxUpdateManagerTest.ts | 2 +- tests/perf-test/ChatFinderPage.perf-test.tsx | 6 +++--- tests/perf-test/OptionsListUtils.perf-test.ts | 4 ++-- .../ReportActionCompose.perf-test.tsx | 20 ++++++++----------- .../perf-test/ReportActionsList.perf-test.tsx | 4 ++-- tests/perf-test/ReportScreen.perf-test.tsx | 8 ++++---- tests/ui/UnreadIndicatorsTest.tsx | 4 ++-- tests/utils/LHNTestUtils.tsx | 6 +++--- 9 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/libs/actions/OnyxUpdateManager/utils/__mocks__/index.ts b/src/libs/actions/OnyxUpdateManager/utils/__mocks__/index.ts index b4d97a4399db..f66e059ff7f6 100644 --- a/src/libs/actions/OnyxUpdateManager/utils/__mocks__/index.ts +++ b/src/libs/actions/OnyxUpdateManager/utils/__mocks__/index.ts @@ -3,7 +3,7 @@ import createProxyForObject from '@src/utils/createProxyForObject'; import type * as OnyxUpdateManagerUtilsImport from '..'; import {applyUpdates} from './applyUpdates'; -const UtilsImplementation: typeof OnyxUpdateManagerUtilsImport = jest.requireActual('@libs/actions/OnyxUpdateManager/utils'); +const UtilsImplementation = jest.requireActual('@libs/actions/OnyxUpdateManager/utils'); type OnyxUpdateManagerUtilsMockValues = { onValidateAndApplyDeferredUpdates: ((clientLastUpdateID?: number) => Promise) | undefined; diff --git a/tests/actions/OnyxUpdateManagerTest.ts b/tests/actions/OnyxUpdateManagerTest.ts index d1a10f8a4775..3a4ff0779217 100644 --- a/tests/actions/OnyxUpdateManagerTest.ts +++ b/tests/actions/OnyxUpdateManagerTest.ts @@ -20,7 +20,7 @@ import createOnyxMockUpdate from '../utils/createOnyxMockUpdate'; jest.mock('@libs/actions/App'); jest.mock('@libs/actions/OnyxUpdateManager/utils'); jest.mock('@libs/actions/OnyxUpdateManager/utils/applyUpdates', () => { - const ApplyUpdatesImplementation: typeof ApplyUpdatesImport = jest.requireActual('@libs/actions/OnyxUpdateManager/utils/applyUpdates'); + const ApplyUpdatesImplementation = jest.requireActual('@libs/actions/OnyxUpdateManager/utils/applyUpdates'); return { applyUpdates: jest.fn((updates: DeferredUpdatesDictionary) => ApplyUpdatesImplementation.applyUpdates(updates)), diff --git a/tests/perf-test/ChatFinderPage.perf-test.tsx b/tests/perf-test/ChatFinderPage.perf-test.tsx index 55430b2a9d48..fda81265bdc0 100644 --- a/tests/perf-test/ChatFinderPage.perf-test.tsx +++ b/tests/perf-test/ChatFinderPage.perf-test.tsx @@ -27,7 +27,7 @@ import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; jest.mock('lodash/debounce', () => - jest.fn((fn: Record>) => { + jest.fn((fn: Record) => { // eslint-disable-next-line no-param-reassign fn.cancel = jest.fn(); return fn; @@ -50,7 +50,7 @@ jest.mock('@src/libs/Navigation/Navigation', () => ({ })); jest.mock('@react-navigation/native', () => { - const actualNav = jest.requireActual('@react-navigation/native'); + const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, useFocusEffect: jest.fn(), @@ -67,7 +67,7 @@ jest.mock('@react-navigation/native', () => { getCurrentRoute: () => jest.fn(), getState: () => jest.fn(), }), - } as typeof NativeNavigation; + }; }); jest.mock('@src/components/withNavigationFocus', () => (Component: ComponentType) => { diff --git a/tests/perf-test/OptionsListUtils.perf-test.ts b/tests/perf-test/OptionsListUtils.perf-test.ts index ddd441f8fae2..16522297a416 100644 --- a/tests/perf-test/OptionsListUtils.perf-test.ts +++ b/tests/perf-test/OptionsListUtils.perf-test.ts @@ -64,13 +64,13 @@ const mockedPersonalDetailsMap = getMockedPersonalDetails(PERSONAL_DETAILS_LIST_ const mockedBetas = Object.values(CONST.BETAS); jest.mock('@react-navigation/native', () => { - const actualNav = jest.requireActual('@react-navigation/native'); + const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, createNavigationContainerRef: () => ({ getState: () => jest.fn(), }), - } as typeof NativeNavigation; + }; }); const options = OptionsListUtils.createOptionList(personalDetails, reports); diff --git a/tests/perf-test/ReportActionCompose.perf-test.tsx b/tests/perf-test/ReportActionCompose.perf-test.tsx index 28987e6b58ed..eee372ceb659 100644 --- a/tests/perf-test/ReportActionCompose.perf-test.tsx +++ b/tests/perf-test/ReportActionCompose.perf-test.tsx @@ -21,17 +21,13 @@ import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; // mock PortalStateContext jest.mock('@gorhom/portal'); -jest.mock( - 'react-native-reanimated', - () => - ({ - ...jest.requireActual('react-native-reanimated/mock'), - useAnimatedRef: jest.fn(), - } as typeof Animated), -); +jest.mock('react-native-reanimated', () => ({ + ...jest.requireActual('react-native-reanimated/mock'), + useAnimatedRef: jest.fn(), +})); jest.mock('@react-navigation/native', () => { - const actualNav = jest.requireActual('@react-navigation/native'); + const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, useNavigation: () => ({ @@ -40,11 +36,11 @@ jest.mock('@react-navigation/native', () => { }), useIsFocused: () => true, useNavigationState: () => {}, - } as typeof Navigation; + }; }); jest.mock('@src/libs/actions/EmojiPickerAction', () => { - const actualEmojiPickerAction = jest.requireActual('@src/libs/actions/EmojiPickerAction'); + const actualEmojiPickerAction = jest.requireActual('@src/libs/actions/EmojiPickerAction'); return { ...actualEmojiPickerAction, emojiPickerRef: { @@ -55,7 +51,7 @@ jest.mock('@src/libs/actions/EmojiPickerAction', () => { showEmojiPicker: jest.fn(), hideEmojiPicker: jest.fn(), isActive: () => true, - } as EmojiPickerRef; + }; }); jest.mock('@src/components/withNavigationFocus', () => (Component: ComponentType) => { diff --git a/tests/perf-test/ReportActionsList.perf-test.tsx b/tests/perf-test/ReportActionsList.perf-test.tsx index 17b27c6905cc..85a4df7f307e 100644 --- a/tests/perf-test/ReportActionsList.perf-test.tsx +++ b/tests/perf-test/ReportActionsList.perf-test.tsx @@ -53,12 +53,12 @@ jest.mock('@components/withCurrentUserPersonalDetails', () => { }); jest.mock('@react-navigation/native', () => { - const actualNav = jest.requireActual('@react-navigation/native'); + const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, useRoute: () => mockedNavigate, useIsFocused: () => true, - } as typeof Navigation; + }; }); jest.mock('@src/components/ConfirmedRoute.tsx'); diff --git a/tests/perf-test/ReportScreen.perf-test.tsx b/tests/perf-test/ReportScreen.perf-test.tsx index d452e9412655..c960af0c46f0 100644 --- a/tests/perf-test/ReportScreen.perf-test.tsx +++ b/tests/perf-test/ReportScreen.perf-test.tsx @@ -42,13 +42,13 @@ jest.mock('@src/libs/API', () => ({ })); jest.mock('react-native-reanimated', () => { - const actualNav = jest.requireActual('react-native-reanimated/mock'); + const actualNav = jest.requireActual('react-native-reanimated/mock'); return { ...actualNav, useSharedValue: jest.fn, useAnimatedStyle: jest.fn, useAnimatedRef: jest.fn, - } as typeof Animated; + }; }); jest.mock('@src/components/ConfirmedRoute.tsx'); @@ -90,7 +90,7 @@ jest.mock('@src/libs/Navigation/Navigation', () => ({ })); jest.mock('@react-navigation/native', () => { - const actualNav = jest.requireActual('@react-navigation/native'); + const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, useFocusEffect: jest.fn(), @@ -102,7 +102,7 @@ jest.mock('@react-navigation/native', () => { }), useNavigationState: () => {}, createNavigationContainerRef: jest.fn(), - } as typeof Navigation; + }; }); // mock PortalStateContext diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index a9318dff217a..e849e942938c 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -91,7 +91,7 @@ const createAddListenerMock = (): ListenerMock => { }; jest.mock('@react-navigation/native', () => { - const actualNav: jest.Mocked = jest.requireActual('@react-navigation/native'); + const actualNav = jest.requireActual('@react-navigation/native'); const {triggerTransitionEnd, addListener} = createAddListenerMock(); transitionEndCB = triggerTransitionEnd; @@ -110,7 +110,7 @@ jest.mock('@react-navigation/native', () => { getState: () => ({ routes: [], }), - } as typeof NativeNavigation; + }; }); beforeAll(() => { diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 89c31d92843e..7a9977138227 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -33,8 +33,8 @@ type MockedSidebarLinksProps = { currentReportID?: string; }; -jest.mock('@react-navigation/native', (): typeof Navigation => { - const actualNav = jest.requireActual('@react-navigation/native'); +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, useRoute: jest.fn(), @@ -45,7 +45,7 @@ jest.mock('@react-navigation/native', (): typeof Navigation => { addListener: jest.fn(), }), createNavigationContainerRef: jest.fn(), - } as typeof Navigation; + }; }); const fakePersonalDetails: PersonalDetailsList = { From 4b6d7d45de7974fe23b9f1b2921d81a600dba7aa Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 14:52:17 +0200 Subject: [PATCH 12/34] Add assertion to other Json.parse --- src/components/IFrame.tsx | 2 +- src/libs/Notification/PushNotification/index.native.ts | 4 ++-- .../PushNotification/shouldShowPushNotification.ts | 4 ++-- .../Notification/clearReportNotifications/index.native.ts | 6 +++--- src/libs/Pusher/pusher.ts | 2 +- tests/unit/sanitizeStringForJSONParseTest.ts | 7 +++---- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/components/IFrame.tsx b/src/components/IFrame.tsx index 05da3a1edb9c..f492df0f3866 100644 --- a/src/components/IFrame.tsx +++ b/src/components/IFrame.tsx @@ -17,7 +17,7 @@ function getNewDotURL(url: string): string { let params: Record; try { - params = JSON.parse(paramString); + params = JSON.parse(paramString) as Record; } catch { params = {}; } diff --git a/src/libs/Notification/PushNotification/index.native.ts b/src/libs/Notification/PushNotification/index.native.ts index 34699f0610e1..72b36fdc33f7 100644 --- a/src/libs/Notification/PushNotification/index.native.ts +++ b/src/libs/Notification/PushNotification/index.native.ts @@ -1,4 +1,4 @@ -import type {PushPayload} from '@ua/react-native-airship'; +import type {JsonValue, PushPayload} from '@ua/react-native-airship'; import Airship, {EventType} from '@ua/react-native-airship'; import Onyx from 'react-native-onyx'; import Log from '@libs/Log'; @@ -31,7 +31,7 @@ function pushNotificationEventCallback(eventType: EventType, notification: PushP // On Android, some notification payloads are sent as a JSON string rather than an object if (typeof payload === 'string') { - payload = JSON.parse(payload); + payload = JSON.parse(payload) as JsonValue; } const data = payload as PushNotificationData; diff --git a/src/libs/Notification/PushNotification/shouldShowPushNotification.ts b/src/libs/Notification/PushNotification/shouldShowPushNotification.ts index fd6029857ded..f66638657a19 100644 --- a/src/libs/Notification/PushNotification/shouldShowPushNotification.ts +++ b/src/libs/Notification/PushNotification/shouldShowPushNotification.ts @@ -1,4 +1,4 @@ -import type {PushPayload} from '@ua/react-native-airship'; +import type {JsonValue, PushPayload} from '@ua/react-native-airship'; import Log from '@libs/Log'; import * as ReportActionUtils from '@libs/ReportActionsUtils'; import * as Report from '@userActions/Report'; @@ -14,7 +14,7 @@ export default function shouldShowPushNotification(pushPayload: PushPayload): bo // The payload is string encoded on Android if (typeof payload === 'string') { - payload = JSON.parse(payload); + payload = JSON.parse(payload) as JsonValue; } const data = payload as PushNotificationData; diff --git a/src/libs/Notification/clearReportNotifications/index.native.ts b/src/libs/Notification/clearReportNotifications/index.native.ts index 3485df2d5ade..751cac3849e1 100644 --- a/src/libs/Notification/clearReportNotifications/index.native.ts +++ b/src/libs/Notification/clearReportNotifications/index.native.ts @@ -1,4 +1,4 @@ -import type {PushPayload} from '@ua/react-native-airship'; +import type {JsonValue, PushPayload} from '@ua/react-native-airship'; import Airship from '@ua/react-native-airship'; import Log from '@libs/Log'; import type {PushNotificationData} from '@libs/Notification/PushNotification/NotificationType'; @@ -8,7 +8,7 @@ import type ClearReportNotifications from './types'; const parseNotificationAndReportIDs = (pushPayload: PushPayload) => { let payload = pushPayload.extras.payload; if (typeof payload === 'string') { - payload = JSON.parse(payload); + payload = JSON.parse(payload) as JsonValue; } const data = payload as PushNotificationData; return { @@ -34,7 +34,7 @@ const clearReportNotifications: ClearReportNotifications = (reportID: string) => Log.info(`[PushNotification] found ${reportNotificationIDs.length} notifications to clear`, false, {reportID}); reportNotificationIDs.forEach((notificationID) => Airship.push.clearNotification(notificationID)); }) - .catch((error) => { + .catch((error: Error) => { Log.alert(`${CONST.ERROR.ENSURE_BUGBOT} [PushNotification] BrowserNotifications.clearReportNotifications threw an error. This should never happen.`, {reportID, error}); }); }; diff --git a/src/libs/Pusher/pusher.ts b/src/libs/Pusher/pusher.ts index 35864d1b6f2e..a092869cdbdc 100644 --- a/src/libs/Pusher/pusher.ts +++ b/src/libs/Pusher/pusher.ts @@ -170,7 +170,7 @@ function bindEventToChannel(channel: Channel let data: EventData; try { - data = isObject(eventData) ? eventData : JSON.parse(eventData as string); + data = isObject(eventData) ? eventData : (JSON.parse(eventData) as EventData); } catch (err) { Log.alert('[Pusher] Unable to parse single JSON event data from Pusher', {error: err, eventData}); return; diff --git a/tests/unit/sanitizeStringForJSONParseTest.ts b/tests/unit/sanitizeStringForJSONParseTest.ts index e269617d4f24..da09aa346db9 100644 --- a/tests/unit/sanitizeStringForJSONParseTest.ts +++ b/tests/unit/sanitizeStringForJSONParseTest.ts @@ -41,16 +41,15 @@ describe('santizeStringForJSONParse', () => { describe.each(invalidJSONData)('canHandleInvalidJSON', (input, expectedOutput) => { test('sanitizeStringForJSONParse', () => { const badJSON = `{"key": "${input}"}`; - // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- it's supposed to throw an error - expect(() => JSON.parse(badJSON)).toThrow(); - const goodJSON: ParsedJSON = JSON.parse(`{"key": "${sanitizeStringForJSONParse(input)}"}`); + expect(() => JSON.parse(badJSON) as unknown).toThrow(); + const goodJSON = JSON.parse(`{"key": "${sanitizeStringForJSONParse(input)}"}`) as ParsedJSON; expect(goodJSON.key).toStrictEqual(expectedOutput); }); }); describe.each(validJSONData)('canHandleValidJSON', (input, expectedOutput) => { test('sanitizeStringForJSONParse', () => { - const goodJSON: ParsedJSON = JSON.parse(`{"key": "${sanitizeStringForJSONParse(input)}"}`); + const goodJSON = JSON.parse(`{"key": "${sanitizeStringForJSONParse(input)}"}`) as ParsedJSON; expect(goodJSON.key).toStrictEqual(expectedOutput); }); }); From 582a0b4f91e3730fa7a2b54ff5f145ecf2d5ddc8 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 15:00:02 +0200 Subject: [PATCH 13/34] Add generic types to requires --- tests/unit/markPullRequestsAsDeployedTest.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/unit/markPullRequestsAsDeployedTest.ts b/tests/unit/markPullRequestsAsDeployedTest.ts index 8d8b25968a28..bf90921452ba 100644 --- a/tests/unit/markPullRequestsAsDeployedTest.ts +++ b/tests/unit/markPullRequestsAsDeployedTest.ts @@ -138,7 +138,7 @@ beforeAll(() => { jest.mock('../../.github/libs/ActionUtils', () => ({ getJSONInput: jest.fn().mockImplementation((name: string, defaultValue: string) => { try { - const input: string = mockGetInput(name); + const input = mockGetInput(name) as string; return JSON.parse(input) as unknown; } catch (err) { return defaultValue; @@ -171,10 +171,12 @@ afterAll(() => { jest.clearAllMocks(); }); +type MockedActionRun = () => Promise; + describe('markPullRequestsAsDeployed', () => { it('comments on pull requests correctly for a standard staging deploy', async () => { // Note: we import this in here so that it executes after all the mocks are set up - run = require('../../.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed'); + run = require('../../.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed'); await run(); expect(mockCreateComment).toHaveBeenCalledTimes(Object.keys(PRList).length); for (let i = 0; i < Object.keys(PRList).length; i++) { @@ -204,7 +206,7 @@ platform | result }); // Note: we import this in here so that it executes after all the mocks are set up - run = require('../../.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed'); + run = require('../../.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed'); await run(); expect(mockCreateComment).toHaveBeenCalledTimes(Object.keys(PRList).length); @@ -260,7 +262,7 @@ platform | result }); // Note: we import this in here so that it executes after all the mocks are set up - run = require('../../.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed'); + run = require('../../.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed'); await run(); expect(mockCreateComment).toHaveBeenCalledTimes(1); expect(mockCreateComment).toHaveBeenCalledWith({ @@ -295,7 +297,7 @@ platform | result }); // Note: we import this in here so that it executes after all the mocks are set up - run = require('../../.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed'); + run = require('../../.github/actions/javascript/markPullRequestsAsDeployed/markPullRequestsAsDeployed'); await run(); expect(mockCreateComment).toHaveBeenCalledTimes(Object.keys(PRList).length); for (let i = 0; i < Object.keys(PRList).length; i++) { From a7fee2d833cde8c01ea57a5560b9b75390165712 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 15:32:52 +0200 Subject: [PATCH 14/34] Mock middleware properly --- tests/unit/RequestTest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/RequestTest.ts b/tests/unit/RequestTest.ts index bb444717ad41..74c42cdf02c4 100644 --- a/tests/unit/RequestTest.ts +++ b/tests/unit/RequestTest.ts @@ -18,8 +18,8 @@ const request: OnyxTypes.Request = { }; test('Request.use() can register a middleware and it will run', () => { - const testMiddleware = jest.fn(); - Request.use(testMiddleware); + const testMiddleware = jest.fn>(); + Request.use(testMiddleware as unknown as Middleware); Request.processWithMiddleware(request, true); return waitForBatchedUpdates().then(() => { From 14e458831a3c8df33e65f95b52aed48ac927a1a9 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 15:34:44 +0200 Subject: [PATCH 15/34] Assert that prop is a string --- tests/ui/UnreadIndicatorsTest.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index e849e942938c..41415f39fc4b 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -478,7 +478,7 @@ describe('Unread Indicators', () => { const newMessageLineIndicatorHintText = Localize.translateLocal('accessibilityHints.newMessageLineIndicator'); const unreadIndicator = screen.queryAllByLabelText(newMessageLineIndicatorHintText); expect(unreadIndicator).toHaveLength(1); - const reportActionID = unreadIndicator[0]?.props?.['data-action-id']; + const reportActionID = unreadIndicator[0]?.props?.['data-action-id'] as string; expect(reportActionID).toBe('3'); // Scroll up and verify the new messages badge appears scrollUpToRevealNewMessagesBadge(); From c3cab6b66ea7914319199c29c396c28de5972b42 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 15:35:15 +0200 Subject: [PATCH 16/34] Add missing args to octokit mocked functions --- tests/unit/GithubUtilsTest.ts | 4 +++- tests/unit/createOrUpdateStagingDeployTest.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/unit/GithubUtilsTest.ts b/tests/unit/GithubUtilsTest.ts index 0ff25d16d06c..b157f105f469 100644 --- a/tests/unit/GithubUtilsTest.ts +++ b/tests/unit/GithubUtilsTest.ts @@ -34,6 +34,8 @@ type ObjectMethodData = { data: T; }; +type OctokitCreateIssue = InternalOctokit['rest']['issues']['create']; + const asMutable = (value: T): Writable => value as Writable; beforeAll(() => { @@ -44,7 +46,7 @@ beforeAll(() => { const moctokit = { rest: { issues: { - create: jest.fn().mockImplementation((arg) => + create: jest.fn().mockImplementation((arg: Parameters[0]) => Promise.resolve({ data: { ...arg, diff --git a/tests/unit/createOrUpdateStagingDeployTest.ts b/tests/unit/createOrUpdateStagingDeployTest.ts index 59ebe9d639cf..8cd340f317c7 100644 --- a/tests/unit/createOrUpdateStagingDeployTest.ts +++ b/tests/unit/createOrUpdateStagingDeployTest.ts @@ -34,7 +34,7 @@ beforeAll(() => { const moctokit = { rest: { issues: { - create: jest.fn().mockImplementation((arg) => + create: jest.fn().mockImplementation((arg: Arguments) => Promise.resolve({ data: { ...arg, From 88de71a4370f4b47682dc5f5c56336747e839bf7 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 16:06:34 +0200 Subject: [PATCH 17/34] Add type for backgroundColor --- src/styles/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index b031e665594f..fd81203a428a 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -784,7 +784,7 @@ const styles = (theme: ThemeColors) => height: 140, }, - pickerSmall: (disabled = false, backgroundColor = theme.highlightBG) => + pickerSmall: (disabled = false, backgroundColor: string = theme.highlightBG) => ({ inputIOS: { fontFamily: FontUtils.fontFamily.platform.EXP_NEUE, @@ -1283,7 +1283,7 @@ const styles = (theme: ThemeColors) => zIndex: 1, }, - picker: (disabled = false, backgroundColor = theme.appBG) => + picker: (disabled = false, backgroundColor: string = theme.appBG) => ({ iconContainer: { top: Math.round(variables.inputHeight * 0.5) - 11, @@ -1546,7 +1546,7 @@ const styles = (theme: ThemeColors) => borderColor: theme.success, }, - statusIndicator: (backgroundColor = theme.danger) => + statusIndicator: (backgroundColor: string = theme.danger) => ({ borderColor: theme.sidebar, backgroundColor, @@ -1560,7 +1560,7 @@ const styles = (theme: ThemeColors) => zIndex: 10, } satisfies ViewStyle), - bottomTabStatusIndicator: (backgroundColor = theme.danger) => ({ + bottomTabStatusIndicator: (backgroundColor: string = theme.danger) => ({ borderColor: theme.sidebar, backgroundColor, borderRadius: 8, From 1f3cd34c6b723b11192e5315db25085112672b7a Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 16:06:57 +0200 Subject: [PATCH 18/34] Fix minor type issues --- src/components/MagicCodeInput.tsx | 2 +- src/pages/workspace/WorkspaceMembersPage.tsx | 5 ++--- tests/ui/UnreadIndicatorsTest.tsx | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/MagicCodeInput.tsx b/src/components/MagicCodeInput.tsx index 6239243cb5ab..956f3ffe5e02 100644 --- a/src/components/MagicCodeInput.tsx +++ b/src/components/MagicCodeInput.tsx @@ -298,7 +298,7 @@ function MagicCodeInput( // Fill the array with empty characters if there are no inputs. if (focusedIndex === 0 && !hasInputs) { - numbers = Array(maxLength).fill(CONST.MAGIC_CODE_EMPTY_CHAR); + numbers = Array(maxLength).fill(CONST.MAGIC_CODE_EMPTY_CHAR); // Deletes the value of the previous input and focuses on it. } else if (focusedIndex && focusedIndex !== 0) { diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 6ed851c70f4e..35d725c66e17 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -64,9 +64,8 @@ type WorkspaceMembersPageProps = WithPolicyAndFullscreenLoadingProps & * Inverts an object, equivalent of _.invert */ function invertObject(object: Record): Record { - const invertedEntries = Object.entries(object).map(([key, value]) => [value, key]); - const inverted: Record = Object.fromEntries(invertedEntries); - return inverted; + const invertedEntries = Object.entries(object).map(([key, value]) => [value, key] as const); + return Object.fromEntries(invertedEntries); } type MemberOption = Omit & {accountID: number}; diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 41415f39fc4b..2b1cabae5a80 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -321,7 +321,7 @@ describe('Unread Indicators', () => { const newMessageLineIndicatorHintText = Localize.translateLocal('accessibilityHints.newMessageLineIndicator'); const unreadIndicator = screen.queryAllByLabelText(newMessageLineIndicatorHintText); expect(unreadIndicator).toHaveLength(1); - const reportActionID = unreadIndicator[0]?.props?.['data-action-id']; + const reportActionID = unreadIndicator[0]?.props?.['data-action-id'] as string; expect(reportActionID).toBe('4'); // Scroll up and verify that the "New messages" badge appears scrollUpToRevealNewMessagesBadge(); From 1141173811a89f86e948033430d8cce315a80a16 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 16:08:54 +0200 Subject: [PATCH 19/34] Augment objectContaining and arrayContaining to return unknown instead of any --- src/types/modules/jest.d.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/types/modules/jest.d.ts diff --git a/src/types/modules/jest.d.ts b/src/types/modules/jest.d.ts new file mode 100644 index 000000000000..532437d2f7cf --- /dev/null +++ b/src/types/modules/jest.d.ts @@ -0,0 +1,13 @@ +declare global { + namespace jest { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions + interface Expect { + // eslint-disable-next-line @typescript-eslint/ban-types + objectContaining(obj: E): unknown; + arrayContaining(arr: readonly E[]): unknown; + } + } +} + +// We used the export {} line to mark this file as an external module +export {}; From 31f64f432da9afb22aee9d87aa6970f38c56e03d Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 16:21:54 +0200 Subject: [PATCH 20/34] Fix minor errors --- __mocks__/@ua/react-native-airship.ts | 16 ++++++++-------- __mocks__/fs.ts | 1 + __mocks__/react-native.ts | 4 ++-- desktop/main.ts | 2 +- src/components/OfflineWithFeedback.tsx | 2 +- src/components/Tooltip/PopoverAnchorTooltip.tsx | 2 +- src/libs/E2E/utils/NetworkInterceptor.ts | 2 +- src/libs/Navigation/linkTo/index.ts | 2 +- src/libs/OptionsListUtils.ts | 4 ++-- src/libs/actions/Session/index.ts | 2 +- src/libs/fileDownload/index.ios.ts | 2 +- src/pages/settings/Wallet/ExpensifyCardPage.tsx | 2 +- src/utils/createProxyForObject.ts | 2 +- tests/perf-test/ReportActionsUtils.perf-test.ts | 4 ++-- 14 files changed, 24 insertions(+), 23 deletions(-) diff --git a/__mocks__/@ua/react-native-airship.ts b/__mocks__/@ua/react-native-airship.ts index ae7661ab672f..14909b58b31c 100644 --- a/__mocks__/@ua/react-native-airship.ts +++ b/__mocks__/@ua/react-native-airship.ts @@ -15,31 +15,31 @@ const iOS: Partial = { }, }; -const pushIOS: AirshipPushIOS = jest.fn().mockImplementation(() => ({ +const pushIOS = jest.fn().mockImplementation(() => ({ setBadgeNumber: jest.fn(), setForegroundPresentationOptions: jest.fn(), setForegroundPresentationOptionsCallback: jest.fn(), -}))(); +}))() as AirshipPushIOS; -const pushAndroid: AirshipPushAndroid = jest.fn().mockImplementation(() => ({ +const pushAndroid = jest.fn().mockImplementation(() => ({ setForegroundDisplayPredicate: jest.fn(), -}))(); +}))() as AirshipPushAndroid; -const push: AirshipPush = jest.fn().mockImplementation(() => ({ +const push = jest.fn().mockImplementation(() => ({ iOS: pushIOS, android: pushAndroid, enableUserNotifications: () => Promise.resolve(false), clearNotifications: jest.fn(), getNotificationStatus: () => Promise.resolve({airshipOptIn: false, systemEnabled: false, airshipEnabled: false}), getActiveNotifications: () => Promise.resolve([]), -}))(); +}))() as AirshipPush; -const contact: AirshipContact = jest.fn().mockImplementation(() => ({ +const contact = jest.fn().mockImplementation(() => ({ identify: jest.fn(), getNamedUserId: () => Promise.resolve(undefined), reset: jest.fn(), module: jest.fn(), -}))(); +}))() as AirshipContact; const Airship: Partial = { addListener: jest.fn(), diff --git a/__mocks__/fs.ts b/__mocks__/fs.ts index cca0aa9520ec..3f8579557c82 100644 --- a/__mocks__/fs.ts +++ b/__mocks__/fs.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ const {fs} = require('memfs'); module.exports = fs; diff --git a/__mocks__/react-native.ts b/__mocks__/react-native.ts index 27b78b308446..f0cd99825c3d 100644 --- a/__mocks__/react-native.ts +++ b/__mocks__/react-native.ts @@ -41,7 +41,7 @@ jest.doMock('react-native', () => { }; }; - const reactNativeMock: ReactNativeMock = Object.setPrototypeOf( + const reactNativeMock = Object.setPrototypeOf( { NativeModules: { ...ReactNative.NativeModules, @@ -102,7 +102,7 @@ jest.doMock('react-native', () => { }, }, ReactNative, - ); + ) as ReactNativeMock; return reactNativeMock; }); diff --git a/desktop/main.ts b/desktop/main.ts index cb541ca87279..2c802b1e590a 100644 --- a/desktop/main.ts +++ b/desktop/main.ts @@ -141,7 +141,7 @@ const manuallyCheckForUpdates = (menuItem?: MenuItem, browserWindow?: BrowserWin autoUpdater .checkForUpdates() - .catch((error) => { + .catch((error: Error) => { isSilentUpdating = false; return {error}; }) diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index 70354c4a4676..c12e73280c7d 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -106,7 +106,7 @@ function OfflineWithFeedback({ return child; } - const childProps: {children: React.ReactNode | undefined; style: AllStyles} = child.props; + const childProps = child.props as {children: React.ReactNode | undefined; style: AllStyles}; const props: StrikethroughProps = { style: StyleUtils.combineStyles(childProps.style, styles.offlineFeedback.deleted, styles.userSelectNone), }; diff --git a/src/components/Tooltip/PopoverAnchorTooltip.tsx b/src/components/Tooltip/PopoverAnchorTooltip.tsx index 693de83fa5d7..7b6ebfd14258 100644 --- a/src/components/Tooltip/PopoverAnchorTooltip.tsx +++ b/src/components/Tooltip/PopoverAnchorTooltip.tsx @@ -10,7 +10,7 @@ function PopoverAnchorTooltip({shouldRender = true, children, ...props}: Tooltip const isPopoverRelatedToTooltipOpen = useMemo(() => { // eslint-disable-next-line @typescript-eslint/dot-notation - const tooltipNode: Node | null = tooltipRef.current?.['_childNode'] ?? null; + const tooltipNode = (tooltipRef.current?.['_childNode'] as Node) ?? null; if ( isOpen && diff --git a/src/libs/E2E/utils/NetworkInterceptor.ts b/src/libs/E2E/utils/NetworkInterceptor.ts index ad23afeb0c3b..511c8014f0cd 100644 --- a/src/libs/E2E/utils/NetworkInterceptor.ts +++ b/src/libs/E2E/utils/NetworkInterceptor.ts @@ -26,7 +26,7 @@ function getFetchRequestHeadersAsObject(fetchRequest: RequestInit): Record { - headers[key] = value; + headers[key] = value as string; }); } return headers; diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 337dbb2b6088..262975cac298 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -69,7 +69,7 @@ export default function linkTo(navigation: NavigationContainerRef): Category[] { const sortedCategories = Object.values(categories).sort((a, b) => a.name.localeCompare(b.name)); // An object that respects nesting of categories. Also, can contain only uniq categories. - const hierarchy = {}; + const hierarchy: Hierarchy = {}; /** * Iterates over all categories to set each category in a proper place in hierarchy * It gets a path based on a category name e.g. "Parent: Child: Subcategory" -> "Parent.Child.Subcategory". @@ -978,7 +978,7 @@ function sortCategories(categories: Record): Category[] { */ sortedCategories.forEach((category) => { const path = category.name.split(CONST.PARENT_CHILD_SEPARATOR); - const existedValue = lodashGet(hierarchy, path, {}); + const existedValue = lodashGet(hierarchy, path, {}) as Hierarchy; lodashSet(hierarchy, path, { ...existedValue, name: category.name, diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index e85fdc9d1531..8c931c1171f1 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -768,7 +768,7 @@ function authenticatePusher(socketID: string, channelName: string, callback: Cha Log.info('[PusherAuthorizer] Pusher authenticated successfully', false, {channelName}); callback(null, response as ChannelAuthorizationData); }) - .catch((error) => { + .catch((error: Error) => { Log.hmmm('[PusherAuthorizer] Unhandled error: ', {channelName, error}); callback(new Error('AuthenticatePusher request failed'), {auth: ''}); }); diff --git a/src/libs/fileDownload/index.ios.ts b/src/libs/fileDownload/index.ios.ts index 0e6701dbda3a..b1617bb440d0 100644 --- a/src/libs/fileDownload/index.ios.ts +++ b/src/libs/fileDownload/index.ios.ts @@ -44,7 +44,7 @@ function downloadVideo(fileUrl: string, fileName: string): Promise { - documentPathUri = attachment.data; + documentPathUri = attachment.data as string | null; if (!documentPathUri) { throw new Error('Error downloading video'); } diff --git a/src/pages/settings/Wallet/ExpensifyCardPage.tsx b/src/pages/settings/Wallet/ExpensifyCardPage.tsx index 02bb5dd99687..2f0f93cbd8b2 100644 --- a/src/pages/settings/Wallet/ExpensifyCardPage.tsx +++ b/src/pages/settings/Wallet/ExpensifyCardPage.tsx @@ -122,7 +122,7 @@ function ExpensifyCardPage({ [revealedCardID]: '', })); }) - .catch((error) => { + .catch((error: string) => { setCardsDetailsErrors((prevState) => ({ ...prevState, [revealedCardID]: error, diff --git a/src/utils/createProxyForObject.ts b/src/utils/createProxyForObject.ts index c18e5e30a0d9..c5055845d5da 100644 --- a/src/utils/createProxyForObject.ts +++ b/src/utils/createProxyForObject.ts @@ -12,7 +12,7 @@ const createProxyForObject = >(value: Valu return target[property]; }, - set: (target, property, newValue) => { + set: (target, property, newValue: Value[string]) => { if (typeof property === 'symbol') { return false; } diff --git a/tests/perf-test/ReportActionsUtils.perf-test.ts b/tests/perf-test/ReportActionsUtils.perf-test.ts index f194cd32bbf4..a33a448cfee7 100644 --- a/tests/perf-test/ReportActionsUtils.perf-test.ts +++ b/tests/perf-test/ReportActionsUtils.perf-test.ts @@ -20,13 +20,13 @@ const getMockedReportActionsMap = (reportsLength = 10, actionsPerReportLength = const reportKeysMap = Array.from({length: reportsLength}, (v, i) => { const key = i + 1; - return {[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${key}`]: Object.assign({}, ...mockReportActions)}; + return {[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${key}`]: Object.assign({}, ...mockReportActions) as Partial}; }); return Object.assign({}, ...reportKeysMap) as Partial; }; -const mockedReportActionsMap = getMockedReportActionsMap(2, 10000); +const mockedReportActionsMap: Partial = getMockedReportActionsMap(2, 10000); const reportActions = createCollection( (item) => `${item.reportActionID}`, From 3df366995ca66db9a36100a00b857f7845cdee4f Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 19 Jun 2024 16:25:31 +0200 Subject: [PATCH 21/34] Add more assertions --- src/components/AttachmentModal.tsx | 2 +- src/components/Attachments/AttachmentCarousel/index.tsx | 2 +- src/components/Hoverable/ActiveHoverable.tsx | 4 ++-- src/components/Pressable/PressableWithDelayToggle.tsx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index c56163a3886f..9624fb493547 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -321,7 +321,7 @@ function AttachmentModal({ } let fileObject = data; if ('getAsFile' in data && typeof data.getAsFile === 'function') { - fileObject = data.getAsFile(); + fileObject = data.getAsFile() as FileObject; } if (!fileObject) { return; diff --git a/src/components/Attachments/AttachmentCarousel/index.tsx b/src/components/Attachments/AttachmentCarousel/index.tsx index 947569538d32..0c267ead673a 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -121,7 +121,7 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, return; } - const item: Attachment = entry.item; + const item = entry.item as Attachment; if (entry.index !== null) { setPage(entry.index); setActiveSource(item.source); diff --git a/src/components/Hoverable/ActiveHoverable.tsx b/src/components/Hoverable/ActiveHoverable.tsx index abd48d432953..fd3d4f3d19e8 100644 --- a/src/components/Hoverable/ActiveHoverable.tsx +++ b/src/components/Hoverable/ActiveHoverable.tsx @@ -48,7 +48,7 @@ function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, shouldFreez return; } - const scrollingListener = DeviceEventEmitter.addListener(CONST.EVENTS.SCROLLING, (scrolling) => { + const scrollingListener = DeviceEventEmitter.addListener(CONST.EVENTS.SCROLLING, (scrolling: boolean) => { isScrollingRef.current = scrolling; if (!isScrollingRef.current) { setIsHovered(isHoveredRef.current); @@ -102,7 +102,7 @@ function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, shouldFreez const child = useMemo(() => getReturnValue(children, !isScrollingRef.current && isHovered), [children, isHovered]); - const {onMouseEnter, onMouseLeave, onMouseMove, onBlur}: OnMouseEvents = child.props; + const {onMouseEnter, onMouseLeave, onMouseMove, onBlur} = child.props as OnMouseEvents; const hoverAndForwardOnMouseEnter = useCallback( (e: MouseEvent) => { diff --git a/src/components/Pressable/PressableWithDelayToggle.tsx b/src/components/Pressable/PressableWithDelayToggle.tsx index 86f6c9d8aff8..617811637525 100644 --- a/src/components/Pressable/PressableWithDelayToggle.tsx +++ b/src/components/Pressable/PressableWithDelayToggle.tsx @@ -99,7 +99,7 @@ function PressableWithDelayToggle( return ( Date: Thu, 20 Jun 2024 17:55:05 +0200 Subject: [PATCH 22/34] Fix child props --- src/components/OfflineWithFeedback.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index c12e73280c7d..cc7f6770d87b 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -1,6 +1,6 @@ import {mapValues} from 'lodash'; import React, {useCallback} from 'react'; -import type {ImageStyle, StyleProp, TextStyle, ViewStyle} from 'react-native'; +import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -59,7 +59,7 @@ type OfflineWithFeedbackProps = ChildrenProps & { canDismissError?: boolean; }; -type StrikethroughProps = Partial & {style: Array}; +type StrikethroughProps = Partial & {style: AllStyles[]}; function OfflineWithFeedback({ pendingAction, @@ -106,9 +106,9 @@ function OfflineWithFeedback({ return child; } - const childProps = child.props as {children: React.ReactNode | undefined; style: AllStyles}; + const childProps = child.props as {children?: React.ReactNode; style?: AllStyles}; const props: StrikethroughProps = { - style: StyleUtils.combineStyles(childProps.style, styles.offlineFeedback.deleted, styles.userSelectNone), + style: StyleUtils.combineStyles(childProps.style ?? [], styles.offlineFeedback.deleted, styles.userSelectNone), }; if (childProps.children) { From 206cc3d3db57e60230827a9d8542d7706d31bd84 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 20 Jun 2024 18:28:44 +0200 Subject: [PATCH 23/34] Rerun lint From 82c9d7438608e4a7904781ddf064ff3722c2c367 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 24 Jun 2024 11:56:23 +0200 Subject: [PATCH 24/34] Fix more eslint errors --- tests/ui/UnreadIndicatorsTest.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 9c44958b1731..69ce88032b5d 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -483,7 +483,7 @@ describe('Unread Indicators', () => { // Verify the new line indicator is present, and it's before the action with ID 4 const unreadIndicator = getUnreadIndicator(); expect(unreadIndicator).toHaveLength(1); - const reportActionID = unreadIndicator[0]?.props?.['data-action-id']; + const reportActionID = unreadIndicator[0]?.props?.['data-action-id'] as string; expect(reportActionID).toBe('4'); // simulate delete comment event from Pusher @@ -504,7 +504,7 @@ describe('Unread Indicators', () => { // Verify the new line indicator is now before the action with ID 5 waitFor(() => { const unreadIndicator = getUnreadIndicator(); - const reportActionID = unreadIndicator[0]?.props?.['data-action-id']; + const reportActionID = unreadIndicator[0]?.props?.['data-action-id'] as string; expect(reportActionID).toBe('5'); }), ); From 99cffb59e7f97e17e82bba7af691ec14896252b8 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 25 Jun 2024 15:55:51 +0200 Subject: [PATCH 25/34] Address review comments --- src/components/OfflineWithFeedback.tsx | 3 ++- src/components/Tooltip/PopoverAnchorTooltip.tsx | 2 +- src/libs/Notification/PushNotification/index.native.ts | 4 ++-- .../PushNotification/shouldShowPushNotification.ts | 4 ++-- .../Notification/clearReportNotifications/index.native.ts | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index c61d0345fe82..ac9eda4043e8 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -107,7 +107,8 @@ function OfflineWithFeedback({ return child; } - const childProps = child.props as {children?: React.ReactNode; style?: AllStyles}; + type ChildComponentProps = ChildrenProps & {style?: AllStyles}; + const childProps = child.props as ChildComponentProps; const props: StrikethroughProps = { style: StyleUtils.combineStyles(childProps.style ?? [], styles.offlineFeedback.deleted, styles.userSelectNone), }; diff --git a/src/components/Tooltip/PopoverAnchorTooltip.tsx b/src/components/Tooltip/PopoverAnchorTooltip.tsx index 7b6ebfd14258..5eb1f45dafcc 100644 --- a/src/components/Tooltip/PopoverAnchorTooltip.tsx +++ b/src/components/Tooltip/PopoverAnchorTooltip.tsx @@ -10,7 +10,7 @@ function PopoverAnchorTooltip({shouldRender = true, children, ...props}: Tooltip const isPopoverRelatedToTooltipOpen = useMemo(() => { // eslint-disable-next-line @typescript-eslint/dot-notation - const tooltipNode = (tooltipRef.current?.['_childNode'] as Node) ?? null; + const tooltipNode = (tooltipRef.current?.['_childNode'] as Node | undefined) ?? null; if ( isOpen && diff --git a/src/libs/Notification/PushNotification/index.native.ts b/src/libs/Notification/PushNotification/index.native.ts index 72b36fdc33f7..f8500e35995e 100644 --- a/src/libs/Notification/PushNotification/index.native.ts +++ b/src/libs/Notification/PushNotification/index.native.ts @@ -1,4 +1,4 @@ -import type {JsonValue, PushPayload} from '@ua/react-native-airship'; +import type {PushPayload} from '@ua/react-native-airship'; import Airship, {EventType} from '@ua/react-native-airship'; import Onyx from 'react-native-onyx'; import Log from '@libs/Log'; @@ -31,7 +31,7 @@ function pushNotificationEventCallback(eventType: EventType, notification: PushP // On Android, some notification payloads are sent as a JSON string rather than an object if (typeof payload === 'string') { - payload = JSON.parse(payload) as JsonValue; + payload = JSON.parse(payload) as string; } const data = payload as PushNotificationData; diff --git a/src/libs/Notification/PushNotification/shouldShowPushNotification.ts b/src/libs/Notification/PushNotification/shouldShowPushNotification.ts index f66638657a19..026dcbf4ca4a 100644 --- a/src/libs/Notification/PushNotification/shouldShowPushNotification.ts +++ b/src/libs/Notification/PushNotification/shouldShowPushNotification.ts @@ -1,4 +1,4 @@ -import type {JsonValue, PushPayload} from '@ua/react-native-airship'; +import type {PushPayload} from '@ua/react-native-airship'; import Log from '@libs/Log'; import * as ReportActionUtils from '@libs/ReportActionsUtils'; import * as Report from '@userActions/Report'; @@ -14,7 +14,7 @@ export default function shouldShowPushNotification(pushPayload: PushPayload): bo // The payload is string encoded on Android if (typeof payload === 'string') { - payload = JSON.parse(payload) as JsonValue; + payload = JSON.parse(payload) as string; } const data = payload as PushNotificationData; diff --git a/src/libs/Notification/clearReportNotifications/index.native.ts b/src/libs/Notification/clearReportNotifications/index.native.ts index 751cac3849e1..8bb00718c7b3 100644 --- a/src/libs/Notification/clearReportNotifications/index.native.ts +++ b/src/libs/Notification/clearReportNotifications/index.native.ts @@ -1,4 +1,4 @@ -import type {JsonValue, PushPayload} from '@ua/react-native-airship'; +import type {PushPayload} from '@ua/react-native-airship'; import Airship from '@ua/react-native-airship'; import Log from '@libs/Log'; import type {PushNotificationData} from '@libs/Notification/PushNotification/NotificationType'; @@ -8,7 +8,7 @@ import type ClearReportNotifications from './types'; const parseNotificationAndReportIDs = (pushPayload: PushPayload) => { let payload = pushPayload.extras.payload; if (typeof payload === 'string') { - payload = JSON.parse(payload) as JsonValue; + payload = JSON.parse(payload) as string; } const data = payload as PushNotificationData; return { From bfb70324c9f3ac350fd6645994d5f0fb40fc8c79 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 25 Jun 2024 15:57:14 +0200 Subject: [PATCH 26/34] Fix one more error in tests --- tests/perf-test/ReportScreen.perf-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/perf-test/ReportScreen.perf-test.tsx b/tests/perf-test/ReportScreen.perf-test.tsx index ed279f05fda5..5e609596601d 100644 --- a/tests/perf-test/ReportScreen.perf-test.tsx +++ b/tests/perf-test/ReportScreen.perf-test.tsx @@ -154,7 +154,7 @@ beforeEach(() => { mockListener.remove.mockClear(); // Mock the implementation of addEventListener to return the mockListener - (Dimensions.addEventListener as jest.Mock).mockImplementation((event, callback) => { + (Dimensions.addEventListener as jest.Mock).mockImplementation((event: string, callback: () => void) => { if (event === 'change') { mockListener.callback = callback; return mockListener; From f9578f9644cf0eb3188081f1fcdc389b58a86e30 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 25 Jun 2024 17:09:13 +0200 Subject: [PATCH 27/34] Fix after internal review --- desktop/main.ts | 2 +- src/libs/Navigation/switchPolicyID.ts | 4 ++-- .../Notification/clearReportNotifications/index.native.ts | 2 +- src/libs/actions/Session/index.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/desktop/main.ts b/desktop/main.ts index 2c802b1e590a..d8c46bbbc89b 100644 --- a/desktop/main.ts +++ b/desktop/main.ts @@ -141,7 +141,7 @@ const manuallyCheckForUpdates = (menuItem?: MenuItem, browserWindow?: BrowserWin autoUpdater .checkForUpdates() - .catch((error: Error) => { + .catch((error: unknown) => { isSilentUpdating = false; return {error}; }) diff --git a/src/libs/Navigation/switchPolicyID.ts b/src/libs/Navigation/switchPolicyID.ts index 59461bfc3c8f..29284cfc6483 100644 --- a/src/libs/Navigation/switchPolicyID.ts +++ b/src/libs/Navigation/switchPolicyID.ts @@ -32,11 +32,11 @@ function getActionForBottomTabNavigator(action: StackNavigationAction, state: Na return; } - let name; + let name: string | undefined; let params: Record; if (isCentralPaneName(action.payload.name)) { name = action.payload.name; - params = action.payload.params; + params = action.payload.params as Record; } else { const actionPayloadParams = action.payload.params as ActionPayloadParams; name = actionPayloadParams.screen; diff --git a/src/libs/Notification/clearReportNotifications/index.native.ts b/src/libs/Notification/clearReportNotifications/index.native.ts index 8bb00718c7b3..aabd24719ea8 100644 --- a/src/libs/Notification/clearReportNotifications/index.native.ts +++ b/src/libs/Notification/clearReportNotifications/index.native.ts @@ -34,7 +34,7 @@ const clearReportNotifications: ClearReportNotifications = (reportID: string) => Log.info(`[PushNotification] found ${reportNotificationIDs.length} notifications to clear`, false, {reportID}); reportNotificationIDs.forEach((notificationID) => Airship.push.clearNotification(notificationID)); }) - .catch((error: Error) => { + .catch((error: unknown) => { Log.alert(`${CONST.ERROR.ENSURE_BUGBOT} [PushNotification] BrowserNotifications.clearReportNotifications threw an error. This should never happen.`, {reportID, error}); }); }; diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 8c931c1171f1..01936aac22d3 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -768,7 +768,7 @@ function authenticatePusher(socketID: string, channelName: string, callback: Cha Log.info('[PusherAuthorizer] Pusher authenticated successfully', false, {channelName}); callback(null, response as ChannelAuthorizationData); }) - .catch((error: Error) => { + .catch((error: unknown) => { Log.hmmm('[PusherAuthorizer] Unhandled error: ', {channelName, error}); callback(new Error('AuthenticatePusher request failed'), {auth: ''}); }); From e47f7e1ea5b6341ad87a9e9f8492945e078e2f61 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 1 Jul 2024 15:52:19 +0200 Subject: [PATCH 28/34] Disable rules in debug.ts --- src/libs/Navigation/linkTo/index.ts | 1 + tests/utils/debug.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 19edbedc1e1c..ade1b43d9b33 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -73,6 +73,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Mon, 1 Jul 2024 16:35:55 +0200 Subject: [PATCH 29/34] Fix prettier --- src/libs/Navigation/linkTo/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index ade1b43d9b33..16db8f624c8d 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -73,7 +73,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Tue, 2 Jul 2024 12:56:32 +0200 Subject: [PATCH 30/34] Fix eslint errors --- src/components/Composer/index.tsx | 2 +- src/pages/workspace/WorkspaceMoreFeaturesPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Composer/index.tsx b/src/components/Composer/index.tsx index f4a5174c2602..eb7091cd958c 100755 --- a/src/components/Composer/index.tsx +++ b/src/components/Composer/index.tsx @@ -251,7 +251,7 @@ function Composer( }, []); useEffect(() => { - const scrollingListener = DeviceEventEmitter.addListener(CONST.EVENTS.SCROLLING, (scrolling) => { + const scrollingListener = DeviceEventEmitter.addListener(CONST.EVENTS.SCROLLING, (scrolling: boolean) => { isReportFlatListScrolling.current = scrolling; }); diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index 3810ea30b830..2481d91e178f 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -88,7 +88,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro const isSyncTaxEnabled = !!policy?.connections?.quickbooksOnline?.config?.syncTax || !!policy?.connections?.xero?.config?.importTaxRates; const policyID = policy?.id ?? ''; // @ts-expect-error a new props will be added during feed api implementation - const workspaceAccountID = policy?.workspaceAccountID ?? ''; + const workspaceAccountID = (policy?.workspaceAccountID as string) ?? ''; // @ts-expect-error onyx key will be available after this PR https://github.com/Expensify/App/pull/44469 const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.EXPENSIFY_CARDS_LIST}${workspaceAccountID}_Expensify Card`); // Uncomment this line for testing disabled toggle feature - for c+ From 3d649b36608544b359813607fd6ec27fb33c92f0 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 3 Jul 2024 17:22:12 +0200 Subject: [PATCH 31/34] Add eslint disable to a todo comment --- src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx index fde42d795e6c..a6b699f5217e 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx @@ -132,6 +132,7 @@ function WorkspaceExpensifyCardPage({route}: WorkspaceExpensifyCardPageProps) { style={hovered && styles.hoveredComponentBG} lastFourPAN={item.lastFourPAN ?? ''} // @ts-expect-error TODO: change cardholder to accountID and get personal details with it + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment cardholder={item.cardholder} limit={item.nameValuePairs?.unapprovedExpenseLimit ?? 0} name={item.nameValuePairs?.cardTitle ?? ''} From 45b02a7f0861948e0a55ebbd16b296347049fae4 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 3 Jul 2024 17:32:43 +0200 Subject: [PATCH 32/34] Fix eslint --- src/libs/ExportOnyxState/index.native.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ExportOnyxState/index.native.ts b/src/libs/ExportOnyxState/index.native.ts index 778b7f9f9cb2..5364ee517707 100644 --- a/src/libs/ExportOnyxState/index.native.ts +++ b/src/libs/ExportOnyxState/index.native.ts @@ -11,7 +11,7 @@ const readFromOnyxDatabase = () => db.executeAsync(query, []).then(({rows}) => { // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-unsafe-member-access - const result = rows?._array.map((row) => ({[row?.record_key]: JSON.parse(row?.valueJSON as string)})); + const result = rows?._array.map((row) => ({[row?.record_key]: JSON.parse(row?.valueJSON as string) as string})); resolve(result); }); From 185901fe48c607d9a9754ed99f9bc5aa35e7d774 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 4 Jul 2024 08:56:34 +0200 Subject: [PATCH 33/34] Cast to unknown --- src/libs/ExportOnyxState/index.native.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ExportOnyxState/index.native.ts b/src/libs/ExportOnyxState/index.native.ts index 5364ee517707..bc32b29bc2ab 100644 --- a/src/libs/ExportOnyxState/index.native.ts +++ b/src/libs/ExportOnyxState/index.native.ts @@ -11,7 +11,7 @@ const readFromOnyxDatabase = () => db.executeAsync(query, []).then(({rows}) => { // eslint-disable-next-line no-underscore-dangle, @typescript-eslint/no-unsafe-member-access - const result = rows?._array.map((row) => ({[row?.record_key]: JSON.parse(row?.valueJSON as string) as string})); + const result = rows?._array.map((row) => ({[row?.record_key]: JSON.parse(row?.valueJSON as string) as unknown})); resolve(result); }); From 0cc3676520cf3822a8e8ba4a0f3b13223dc61faa Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 4 Jul 2024 18:51:26 +0200 Subject: [PATCH 34/34] Add eslint disable to a todo comment --- .../workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx index 36aee07ab6b5..66b64b271792 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx @@ -131,6 +131,7 @@ function WorkspaceExpensifyCardListPage({route}: WorkspaceExpensifyCardListPageP style={hovered && styles.hoveredComponentBG} lastFourPAN={item.lastFourPAN ?? ''} // @ts-expect-error TODO: change cardholder to accountID and get personal details with it + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment cardholder={item.cardholder} limit={item.nameValuePairs?.unapprovedExpenseLimit ?? 0} name={item.nameValuePairs?.cardTitle ?? ''}