diff --git a/.eslintrc.js b/.eslintrc.js index 22bb0158bc8e..27014cf9dd7b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -109,7 +109,6 @@ module.exports = { }, rules: { // TypeScript specific rules - '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/prefer-enum-initializers': 'error', '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-non-null-assertion': 'error', diff --git a/.github/actions/javascript/bumpVersion/bumpVersion.ts b/.github/actions/javascript/bumpVersion/bumpVersion.ts index ff43ab9ee5c5..92b81836ce13 100644 --- a/.github/actions/javascript/bumpVersion/bumpVersion.ts +++ b/.github/actions/javascript/bumpVersion/bumpVersion.ts @@ -49,7 +49,7 @@ if (!semanticVersionLevel || !versionUpdater.isValidSemverLevel(semanticVersionL 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 a178d4073cbb..7799ffe7c9ec 100644 --- a/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts +++ b/.github/actions/javascript/getPreviousVersion/getPreviousVersion.ts @@ -11,7 +11,7 @@ function run() { 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})); 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/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', diff --git a/desktop/main.ts b/desktop/main.ts index 6ab0bc6579d7..d8c46bbbc89b 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: unknown) => { isSilentUpdating = false; return {error}; }) @@ -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, 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/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index df027ed6edb4..450a49403215 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -320,7 +320,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 8f4a4446df99..36abe1e2e5ed 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -135,7 +135,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/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/components/FlatList/index.tsx b/src/components/FlatList/index.tsx index f54eddcbeb79..d3e0459a11bb 100644 --- a/src/components/FlatList/index.tsx +++ b/src/components/FlatList/index.tsx @@ -54,7 +54,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/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/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/components/LottieAnimations/index.tsx b/src/components/LottieAnimations/index.tsx index 477ce02cd740..afbc9cd56e28 100644 --- a/src/components/LottieAnimations/index.tsx +++ b/src/components/LottieAnimations/index.tsx @@ -1,80 +1,81 @@ +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, backgroundColor: colors.blue700, }, Plane: { - file: require('@assets/animations/Plane.lottie'), + file: require('@assets/animations/Plane.lottie'), w: 180, h: 200, }, 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/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index 28e1d81b30e4..ac9eda4043e8 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'; @@ -60,7 +60,7 @@ type OfflineWithFeedbackProps = ChildrenProps & { canDismissError?: boolean; }; -type StrikethroughProps = Partial & {style: Array}; +type StrikethroughProps = Partial & {style: AllStyles[]}; function OfflineWithFeedback({ pendingAction, @@ -107,9 +107,10 @@ function OfflineWithFeedback({ return child; } - const childProps: {children: React.ReactNode | undefined; style: AllStyles} = child.props; + type ChildComponentProps = ChildrenProps & {style?: AllStyles}; + const childProps = child.props as ChildComponentProps; 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) { 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 ( { // eslint-disable-next-line @typescript-eslint/dot-notation - const tooltipNode: Node | null = tooltipRef.current?.['_childNode'] ?? null; + const tooltipNode = (tooltipRef.current?.['_childNode'] as Node | undefined) ?? null; if ( isOpen && 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, 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/ExportOnyxState/index.native.ts b/src/libs/ExportOnyxState/index.native.ts index 778b7f9f9cb2..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)})); + const result = rows?._array.map((row) => ({[row?.record_key]: JSON.parse(row?.valueJSON as string) as unknown})); resolve(result); }); diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 2c23cf573248..d8312937ed6f 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -72,7 +72,8 @@ export default function linkTo(navigation: NavigationContainerRef = { 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/libs/Navigation/switchPolicyID.ts b/src/libs/Navigation/switchPolicyID.ts index 0f6477a9ee0e..19626a400b9d 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/PushNotification/index.native.ts b/src/libs/Notification/PushNotification/index.native.ts index 34699f0610e1..f8500e35995e 100644 --- a/src/libs/Notification/PushNotification/index.native.ts +++ b/src/libs/Notification/PushNotification/index.native.ts @@ -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 string; } const data = payload as PushNotificationData; diff --git a/src/libs/Notification/PushNotification/shouldShowPushNotification.ts b/src/libs/Notification/PushNotification/shouldShowPushNotification.ts index fd6029857ded..026dcbf4ca4a 100644 --- a/src/libs/Notification/PushNotification/shouldShowPushNotification.ts +++ b/src/libs/Notification/PushNotification/shouldShowPushNotification.ts @@ -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 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 3485df2d5ade..aabd24719ea8 100644 --- a/src/libs/Notification/clearReportNotifications/index.native.ts +++ b/src/libs/Notification/clearReportNotifications/index.native.ts @@ -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 string; } 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: unknown) => { Log.alert(`${CONST.ERROR.ENSURE_BUGBOT} [PushNotification] BrowserNotifications.clearReportNotifications threw an error. This should never happen.`, {reportID, error}); }); }; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index b952fbe9af4e..7c495e625e10 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -992,7 +992,7 @@ function sortCategories(categories: Record): 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". @@ -1010,7 +1010,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/Pusher/pusher.ts b/src/libs/Pusher/pusher.ts index 25641d985042..a3383dbadb8a 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/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/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/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index db78b94731ae..0c362f870da4 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -773,7 +773,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: unknown) => { Log.hmmm('[PusherAuthorizer] Unhandled error: ', {channelName, error}); callback(new Error('AuthenticatePusher request failed'), {auth: ''}); }); diff --git a/src/libs/actions/__mocks__/App.ts b/src/libs/actions/__mocks__/App.ts index 03744b397597..09fd553a87f3 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, @@ -39,7 +39,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); 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/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 51f1eabf7a45..01e40a2e3326 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -65,9 +65,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/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index 84bdab0af82b..2c966eebeea4 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -91,7 +91,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro !!policy?.connections?.netsuite?.options?.config?.syncOptions?.syncTax; 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) ?? ''; const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`); // Uncomment this line for testing disabled toggle feature - for c+ // const [cardsList = mockedCardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${CONST.EXPENSIFY_CARD.BANK}`); 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 ?? ''} diff --git a/src/styles/index.ts b/src/styles/index.ts index dbaccc79c0a7..687115bc01e2 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -789,7 +789,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, @@ -1288,7 +1288,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, @@ -1557,7 +1557,7 @@ const styles = (theme: ThemeColors) => borderColor: theme.success, }, - statusIndicator: (backgroundColor = theme.danger) => + statusIndicator: (backgroundColor: string = theme.danger) => ({ borderColor: theme.sidebar, backgroundColor, @@ -1571,7 +1571,7 @@ const styles = (theme: ThemeColors) => zIndex: 10, } satisfies ViewStyle), - bottomTabStatusIndicator: (backgroundColor = theme.danger) => ({ + bottomTabStatusIndicator: (backgroundColor: string = theme.danger) => ({ borderColor: theme.sidebar, backgroundColor, borderRadius: 8, diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index f6f24404d928..09df150df0ed 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1224,16 +1224,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, @@ -1262,17 +1258,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 {}; @@ -1349,8 +1339,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 : {}), @@ -1416,8 +1404,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, @@ -1483,35 +1469,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, @@ -1535,12 +1515,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; }, 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 {}; 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/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 9c6cfdae5a5c..e3aaccd1f050 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 56973205fe4b..f0fef9a8e574 100644 --- a/tests/perf-test/ReportActionsList.perf-test.tsx +++ b/tests/perf-test/ReportActionsList.perf-test.tsx @@ -52,12 +52,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/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}`, diff --git a/tests/perf-test/ReportScreen.perf-test.tsx b/tests/perf-test/ReportScreen.perf-test.tsx index 3c1edb1ebaca..5e609596601d 100644 --- a/tests/perf-test/ReportScreen.perf-test.tsx +++ b/tests/perf-test/ReportScreen.perf-test.tsx @@ -63,13 +63,13 @@ jest.mock('react-native', () => { }); 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'); @@ -111,7 +111,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(), @@ -123,7 +123,7 @@ jest.mock('@react-navigation/native', () => { }), useNavigationState: () => {}, createNavigationContainerRef: jest.fn(), - } as typeof Navigation; + }; }); // mock PortalStateContext @@ -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; diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index b5990ee5d002..2e143c4a86eb 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -92,7 +92,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; @@ -111,7 +111,7 @@ jest.mock('@react-navigation/native', () => { getState: () => ({ routes: [], }), - } as typeof NativeNavigation; + }; }); beforeAll(() => { @@ -322,7 +322,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(); @@ -479,7 +479,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(); 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/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(() => { 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, 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++) { 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); }); }); diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 33a8678aa166..5000fda3ab73 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 = { diff --git a/tests/utils/collections/reportActions.ts b/tests/utils/collections/reportActions.ts index 4836120a405b..d492fe9fa30d 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 ReportActionName from '@src/types/onyx/ReportActionName'; import type DeepRecord from '@src/types/utils/DeepRecord'; -const flattenActionNamesValues = (actionNames: DeepRecord) => { +const flattenActionNamesValues = (actionNames: DeepRecord): ReportActionName[] => { let result: ReportActionName[] = []; Object.values(actionNames).forEach((value) => { if (typeof value === 'object') { @@ -35,9 +35,10 @@ const deprecatedReportActions: ReportActionName[] = [ 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: ReportActionName) => !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: ReportActionName) => !deprecatedReportActions.includes(actionType)), + ) as typeof CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, reportActionID: index.toString(), previousReportActionID: (index === 0 ? 0 : index - 1).toString(), actorAccountID: index, diff --git a/tests/utils/debug.ts b/tests/utils/debug.ts index b33acdf1d5d4..c6c88e19376d 100644 --- a/tests/utils/debug.ts +++ b/tests/utils/debug.ts @@ -4,7 +4,7 @@ * the app. */ -/* eslint-disable no-console, testing-library/no-node-access, testing-library/no-debugging-utils, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable no-console, testing-library/no-node-access, testing-library/no-debugging-utils, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access */ import type {NewPlugin} from 'pretty-format'; import prettyFormat, {plugins} from 'pretty-format'; import ReactIs from 'react-is'; 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;