Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check and remove unnecessary @ts-expect-error suppressions #40627

Merged
merged 27 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
da5ac47
Check and remove unnecessary @ts-expect-error suppressions
ZhenjaHorbach Apr 20, 2024
5bed379
Fix ts and unit test issues
ZhenjaHorbach Apr 20, 2024
9c45c25
Check and remove unnecessary @ts-expect-error suppressions x2
ZhenjaHorbach Apr 22, 2024
6f7565d
Fix conflicts
ZhenjaHorbach Apr 29, 2024
1c65f00
Remove some ts-expect-error
ZhenjaHorbach Apr 29, 2024
f895695
Update dom.d types
ZhenjaHorbach Apr 29, 2024
07da9f9
Update react-native-onyx.d and react-navigation.d-Part-1
ZhenjaHorbach Apr 30, 2024
85ec0d6
Fix comments
ZhenjaHorbach May 1, 2024
5f422b0
Fix issues related with react-native-animation and pdf.worker
ZhenjaHorbach May 1, 2024
6d01dd4
Fix ts-issue with this
ZhenjaHorbach May 1, 2024
9c062bc
Fix conflicts
ZhenjaHorbach May 1, 2024
579668d
Fix spaces
ZhenjaHorbach May 1, 2024
8a30f01
Merge branch 'main' into remove-unnecessary-ts-expect-error
ZhenjaHorbach May 6, 2024
e2eb991
Remove some @ts-expect-errors
ZhenjaHorbach May 6, 2024
0a8ecc7
Revert react-navigation changes
ZhenjaHorbach May 6, 2024
8ff5b41
Merge branch 'main' into remove-unnecessary-ts-expect-error
ZhenjaHorbach May 6, 2024
90249ac
Fix types for onSubmitComment inside ReportFooter
ZhenjaHorbach May 6, 2024
a96ebf5
Fix types for TabSelector
ZhenjaHorbach May 6, 2024
70e93db
Fix comments
ZhenjaHorbach May 8, 2024
2c9c4c0
Merge branch 'main' into remove-unnecessary-ts-expect-error
ZhenjaHorbach May 8, 2024
2455f96
Fix PolicyTaxTests
ZhenjaHorbach May 8, 2024
e4e3531
Fix types for perf-tests
ZhenjaHorbach May 8, 2024
f625298
Fix types for awaitStagingDeploys
ZhenjaHorbach May 8, 2024
467ce8d
Merge branch 'main' into remove-unnecessary-ts-expect-error
ZhenjaHorbach May 10, 2024
530549e
Update types for camera
ZhenjaHorbach May 10, 2024
50c5af1
Update branch and fix conflicts
ZhenjaHorbach May 15, 2024
ef878d4
Update IOUTest and remove @ts-expect-error
ZhenjaHorbach May 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/libs/sanitizeStringForJSONParse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const replacer = (str: string): string =>
* Solution partly taken from SO user Gabriel Rodríguez Flores 🙇
* https://stackoverflow.com/questions/52789718/how-to-remove-special-characters-before-json-parse-while-file-reading
*/
const sanitizeStringForJSONParse = (inputString: string): string => {
const sanitizeStringForJSONParse = (inputString: string | number | boolean | null | undefined): string => {
if (typeof inputString !== 'string') {
throw new TypeError('Input must me of type String');
}
Expand Down
4 changes: 1 addition & 3 deletions __mocks__/@react-navigation/native/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import {useIsFocused as realUseIsFocused, useTheme as realUseTheme} from '@react
// We only want these mocked for storybook, not jest
const useIsFocused: typeof realUseIsFocused = process.env.NODE_ENV === 'test' ? realUseIsFocused : () => true;

// @ts-expect-error as we're mocking this function
const useTheme: typeof realUseTheme = process.env.NODE_ENV === 'test' ? realUseTheme : () => ({});
const useTheme = process.env.NODE_ENV === 'test' ? realUseTheme : () => ({});

export * from '@react-navigation/core';
export * from '@react-navigation/native';
export {useIsFocused, useTheme};
4 changes: 3 additions & 1 deletion src/Expensify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ type ExpensifyOnyxProps = {

type ExpensifyProps = ExpensifyOnyxProps;

const SplashScreenHiddenContext = React.createContext({});
type SplashScreenHiddenContextType = {isSplashHidden?: boolean};

const SplashScreenHiddenContext = React.createContext<SplashScreenHiddenContextType>({});

function Expensify({
isCheckingPublicRoom = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ function BaseAnchorForAttachmentsOnly({style, source = '', displayName = '', dow
}}
onPressIn={onPressIn}
onPressOut={onPressOut}
// @ts-expect-error TODO: Remove this once ShowContextMenuContext (https://github.com/Expensify/App/issues/24980) is migrated to TypeScript.
onLongPress={(event) => showContextMenuForReport(event, anchor, report.reportID, action, checkIfContextMenuActive, ReportUtils.isArchivedRoom(report))}
onLongPress={(event) => showContextMenuForReport(event, anchor, report?.reportID ?? '', action, checkIfContextMenuActive, ReportUtils.isArchivedRoom(report))}
shouldUseHapticsOnLongPress
accessibilityLabel={displayName}
role={CONST.ROLE.BUTTON}
Expand Down
1 change: 0 additions & 1 deletion src/components/PDFThumbnail/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-expect-error - This line imports a module from 'pdfjs-dist' package which lacks TypeScript typings.
import pdfWorkerSource from 'pdfjs-dist/legacy/build/pdf.worker';
import React, {useMemo} from 'react';
import {View} from 'react-native';
Expand Down
2 changes: 1 addition & 1 deletion src/components/TabSelector/TabSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function TabSelector({state, navigation, onTabPress = () => {}, position}: TabSe
return position.interpolate({
inputRange,
outputRange: inputRange.map((i) => (affectedTabs.includes(tabIndex) && i === tabIndex ? theme.border : theme.appBG)),
});
}) as unknown as Animated.AnimatedInterpolation<string>;
}
return theme.border;
},
Expand Down
1 change: 0 additions & 1 deletion src/hooks/useAutoFocusInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export default function useAutoFocusInput(): UseAutoFocusInput {
const [isInputInitialized, setIsInputInitialized] = useState(false);
const [isScreenTransitionEnded, setIsScreenTransitionEnded] = useState(false);

// @ts-expect-error TODO: Remove this when Expensify.js is migrated.
const {isSplashHidden} = useContext(Expensify.SplashScreenHiddenContext);

const inputRef = useRef<TextInput | null>(null);
Expand Down
1 change: 0 additions & 1 deletion src/hooks/useTabNavigatorFocus/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ function useTabNavigatorFocus({tabIndex}: UseTabNavigatorFocusParams): boolean {
// We need to get the position animation value on component initialization to determine
// if the tab is focused or not. Since it's an Animated.Value the only synchronous way
// to retrieve the value is to use a private method.
// @ts-expect-error -- __getValue is a private method
// eslint-disable-next-line no-underscore-dangle
const initialTabPositionValue = tabPositionAnimation.__getValue();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type {StackNavigationOptions} from '@react-navigation/stack';
import React from 'react';
import createCustomBottomTabNavigator from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator';
import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
import type {BottomTabNavigatorParamList} from '@libs/Navigation/types';
import type {BottomTabNavigatorParamList, CentralPaneName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types';
import SidebarScreen from '@pages/home/sidebar/SidebarScreen';
import SearchPageBottomTab from '@pages/Search/SearchPageBottomTab';
import SCREENS from '@src/SCREENS';
Expand All @@ -19,7 +19,7 @@ const screenOptions: StackNavigationOptions = {
};

function BottomTabNavigator() {
const activeRoute = useNavigationState(getTopmostCentralPaneRoute);
const activeRoute = useNavigationState<RootStackParamList, NavigationPartialRoute<CentralPaneName> | undefined>(getTopmostCentralPaneRoute);

return (
<ActiveRouteContext.Provider value={activeRoute}>
Expand Down
4 changes: 2 additions & 2 deletions src/libs/Navigation/AppNavigator/getPartialStateDiff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function getPartialStateDiff(state: State<RootStackParamList>, templateState: St
(stateTopmostCentralPane &&
templateStateTopmostCentralPane &&
stateTopmostCentralPane.name !== templateStateTopmostCentralPane.name &&
!shallowCompare(stateTopmostCentralPane.params, templateStateTopmostCentralPane.params))
!shallowCompare(stateTopmostCentralPane.params as Record<string, unknown> | undefined, templateStateTopmostCentralPane.params as Record<string, unknown> | undefined))
) {
// We need to wrap central pane routes in the central pane navigator.
diff[NAVIGATORS.CENTRAL_PANE_NAVIGATOR] = templateStateTopmostCentralPane;
Expand All @@ -73,7 +73,7 @@ function getPartialStateDiff(state: State<RootStackParamList>, templateState: St
(stateTopmostFullScreen &&
templateStateTopmostFullScreen &&
stateTopmostFullScreen.name !== templateStateTopmostFullScreen.name &&
!shallowCompare(stateTopmostFullScreen.params, templateStateTopmostFullScreen.params))
!shallowCompare(stateTopmostFullScreen.params as Record<string, unknown> | undefined, templateStateTopmostFullScreen.params as Record<string, unknown> | undefined))
) {
diff[NAVIGATORS.FULL_SCREEN_NAVIGATOR] = fullScreenDiff;
}
Expand Down
4 changes: 2 additions & 2 deletions src/libs/Navigation/linkTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ export default function linkTo(navigation: NavigationContainerRef<RootStackParam

const isTargetScreenDifferentThanCurrent = Boolean(topmostCentralPaneRoute && topmostCentralPaneRoute.name !== action.payload.params?.screen);
const areParamsDifferent = !shallowCompare(
omitBy(topmostCentralPaneRoute?.params, (value) => value === undefined),
omitBy(action.payload.params?.params, (value) => value === undefined),
omitBy(topmostCentralPaneRoute?.params as Record<string, unknown> | undefined, (value) => value === undefined),
omitBy(action.payload.params?.params as Record<string, unknown> | undefined, (value) => value === undefined),
);
// In case if type is 'FORCED_UP' we replace current screen with the provided. This means the current screen no longer exists in the stack
if (type === CONST.NAVIGATION.TYPE.FORCED_UP) {
Expand Down
8 changes: 4 additions & 4 deletions src/libs/ObjectUtils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// eslint-disable-next-line @typescript-eslint/ban-types
const shallowCompare = (obj1?: object, obj2?: object) => {
const shallowCompare = (obj1?: Record<string, unknown>, obj2?: Record<string, unknown>): boolean => {
if (!obj1 && !obj2) {
return true;
}
if (obj1 && obj2) {
// @ts-expect-error we know that obj1 and obj2 are params of a route.
return Object.keys(obj1).length === Object.keys(obj2).length && Object.keys(obj1).every((key) => obj1[key] === obj2[key]);
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
return keys1.length === keys2.length && keys1.every((key) => obj1[key] === obj2[key]);
}
return false;
};
Expand Down
3 changes: 2 additions & 1 deletion src/libs/ReportActionComposeFocusManager.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';
import type {MutableRefObject} from 'react';
import type {TextInput} from 'react-native';
import ROUTES from '@src/ROUTES';
import Navigation from './Navigation/Navigation';

type FocusCallback = (shouldFocusForNonBlurInputOnTapOutside?: boolean) => void;

const composerRef = React.createRef<TextInput>();
const composerRef: MutableRefObject<TextInput | null> = React.createRef<TextInput>();
const editComposerRef = React.createRef<TextInput>();
// There are two types of composer: general composer (edit composer) and main composer.
// The general composer callback will take priority if it exists.
Expand Down
5 changes: 3 additions & 2 deletions src/libs/Url.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'react-native-url-polyfill/auto';
import type {Route} from '@src/ROUTES';

/**
* Add / to the end of any URL if not present
Expand Down Expand Up @@ -48,12 +49,12 @@ function appendParam(url: string, paramName: string, paramValue: string) {
// If parameter exists, replace it
if (url.includes(`${paramName}=`)) {
const regex = new RegExp(`${paramName}=([^&]*)`);
return url.replace(regex, `${paramName}=${paramValue}`);
return url.replace(regex, `${paramName}=${paramValue}`) as Route;
}

// If parameter doesn't exist, append it
const separator = url.includes('?') ? '&' : '?';
return `${url}${separator}${paramName}=${paramValue}`;
return `${url}${separator}${paramName}=${paramValue}` as Route;
}

function hasURL(text: string) {
Expand Down
20 changes: 8 additions & 12 deletions src/libs/migrations/NVPMigration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import after from 'lodash/after';
import Onyx from 'react-native-onyx';
import type {KeyValueMapping, OnyxEntry} from 'react-native-onyx';
import type {Account} from 'src/types/onyx';
import ONYXKEYS from '@src/ONYXKEYS';
import type {OnyxKey} from '@src/ONYXKEYS';

// These are the oldKeyName: newKeyName of the NVPs we can migrate without any processing
const migrations = {
Expand All @@ -27,35 +30,30 @@ export default function () {

for (const [oldKey, newKey] of Object.entries(migrations)) {
const connectionID = Onyx.connect({
// @ts-expect-error oldKey is a variable
key: oldKey,
key: oldKey as OnyxKey,
callback: (value) => {
Onyx.disconnect(connectionID);
if (value === null) {
resolveWhenDone();
return;
}
// @ts-expect-error These keys are variables, so we can't check the type
Onyx.multiSet({
[newKey]: value,
[oldKey]: null,
}).then(resolveWhenDone);
} as KeyValueMapping).then(resolveWhenDone);
},
});
}
const connectionIDAccount = Onyx.connect({
key: ONYXKEYS.ACCOUNT,
callback: (value) => {
callback: (value: OnyxEntry<Account & {activePolicyID?: string}>) => {
Onyx.disconnect(connectionIDAccount);
// @ts-expect-error we are removing this property, so it is not in the type anymore
if (!value?.activePolicyID) {
resolveWhenDone();
return;
}
// @ts-expect-error we are removing this property, so it is not in the type anymore
const activePolicyID = value.activePolicyID;
const newValue = {...value};
// @ts-expect-error we are removing this property, so it is not in the type anymore
delete newValue.activePolicyID;
Onyx.multiSet({
[ONYXKEYS.NVP_ACTIVE_POLICY_ID]: activePolicyID,
Expand All @@ -72,14 +70,12 @@ export default function () {
resolveWhenDone();
return;
}
const newValue = {};
const newValue = {} as Record<string, unknown>;
for (const key of Object.keys(value)) {
// @ts-expect-error We have no fixed types here
newValue[`nvp_${key}`] = value[key];
// @ts-expect-error We have no fixed types here
newValue[key] = null;
}
Onyx.multiSet(newValue).then(resolveWhenDone);
Onyx.multiSet(newValue as KeyValueMapping).then(resolveWhenDone);
},
});
});
Expand Down
3 changes: 1 addition & 2 deletions src/pages/EnablePayments/AdditionalDetailsStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,7 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO
placeholder={translate('common.phoneNumberPlaceholder')}
shouldSaveDraft
/>
{/* @ts-expect-error TODO: Remove this once DatePicker (https://github.com/Expensify/App/issues/25148) is migrated to TypeScript. */}
<InputWrapper<unknown>
<InputWrapper
InputComponent={DatePicker}
inputID="dob"
containerStyles={[styles.mt4]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ function DateOfBirthUBO({reimbursementAccountDraft, onNext, isEditing, beneficia
submitButtonStyles={[styles.pb5, styles.mb0]}
>
<Text style={[styles.textHeadlineLineHeightXXL]}>{translate('beneficialOwnerInfoStep.enterTheDateOfBirthOfTheOwner')}</Text>
{/* @ts-expect-error TODO: Remove this once DatePicker (https://github.com/Expensify/App/issues/25148) is migrated to TypeScript. */}
<InputWrapper<unknown>
<InputWrapper
InputComponent={DatePicker}
inputID={dobInputID}
label={translate('common.dob')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ function IncorporationDateBusiness({reimbursementAccount, reimbursementAccountDr
submitButtonStyles={[styles.pb5, styles.mb0]}
>
<Text style={[styles.textHeadlineLineHeightXXL]}>{translate('businessInfoStep.selectYourCompanysIncorporationDate')}</Text>
{/* @ts-expect-error TODO: Remove this once DatePicker (https://github.com/Expensify/App/issues/25148) is migrated to TypeScript. */}
<InputWrapper<unknown>
<InputWrapper
InputComponent={DatePicker}
inputID={COMPANY_INCORPORATION_DATE_KEY}
label={translate('businessInfoStep.incorporationDate')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ function DateOfBirth({reimbursementAccount, reimbursementAccountDraft, onNext, i
submitButtonStyles={[styles.pb5, styles.mb0]}
>
<Text style={[styles.textHeadlineLineHeightXXL, styles.mb5]}>{translate('personalInfoStep.enterYourDateOfBirth')}</Text>
{/* @ts-expect-error TODO: Remove this once DatePicker (https://github.com/Expensify/App/issues/25148) is migrated to TypeScript. */}
<InputWrapper<unknown>
<InputWrapper
InputComponent={DatePicker}
inputID={PERSONAL_INFO_DOB_KEY}
label={translate('common.dob')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,6 @@ function ComposerWithSuggestions(
*/
const setTextInputRef = useCallback(
(el: TextInput) => {
// @ts-expect-error need to reassign this ref
ReportActionComposeFocusManager.composerRef.current = el;
textInputRef.current = el;
if (typeof animatedRef === 'function') {
Expand Down Expand Up @@ -649,7 +648,6 @@ function ComposerWithSuggestions(
const unsubscribeNavigationFocus = navigation.addListener('focus', () => {
KeyDownListener.addKeyDownPressListener(focusComposerOnKeyPress);
// The report isn't unmounted and can be focused again after going back from another report so we should update the composerRef again
// @ts-expect-error need to reassign this ref
ReportActionComposeFocusManager.composerRef.current = textInputRef.current;
setUpComposeFocusManager();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import SendButton from './SendButton';
type ComposerRef = {
blur: () => void;
focus: (shouldDelay?: boolean) => void;
replaceSelectionWithText: (text: string, shouldAddTrailSpace: boolean) => void;
replaceSelectionWithText: EmojiPickerActions.OnEmojiSelected;
prepareCommentAndResetComposer: () => string;
isFocused: () => boolean;
};
Expand All @@ -73,9 +73,9 @@ type ReportActionComposeOnyxProps = {

type ReportActionComposeProps = ReportActionComposeOnyxProps &
WithCurrentUserPersonalDetailsProps &
Pick<ComposerWithSuggestionsProps, 'reportID' | 'isEmptyChat' | 'isComposerFullSize' | 'disabled' | 'listHeight' | 'lastReportAction'> & {
Pick<ComposerWithSuggestionsProps, 'reportID' | 'isEmptyChat' | 'isComposerFullSize' | 'listHeight' | 'lastReportAction'> & {
/** A method to call when the form is submitted */
onSubmit: (newComment: string | undefined) => void;
onSubmit: (newComment: string) => void;

/** The report currently being looked at */
report: OnyxEntry<OnyxTypes.Report>;
Expand All @@ -91,6 +91,9 @@ type ReportActionComposeProps = ReportActionComposeOnyxProps &

/** A method to call when the input is blur */
onComposerBlur?: () => void;

/** Should the input be disabled */
disabled?: boolean;
};

// We want consistent auto focus behavior on input between native and mWeb so we have some auto focus management code that will
Expand All @@ -102,7 +105,7 @@ const willBlurTextInputOnTapOutside = willBlurTextInputOnTapOutsideFunc();
function ReportActionCompose({
blockedFromConcierge,
currentUserPersonalDetails = {},
disabled,
disabled = false,
isComposerFullSize = false,
onSubmit,
pendingAction,
Expand Down Expand Up @@ -480,7 +483,6 @@ function ReportActionCompose({
<EmojiPickerButton
isDisabled={isBlockedFromConcierge || disabled}
onModalHide={focus}
// @ts-expect-error TODO: Remove this once EmojiPickerButton (https://github.com/Expensify/App/issues/25155) is migrated to TypeScript.
onEmojiSelected={(...args) => composerRef.current?.replaceSelectionWithText(...args)}
emojiPickerID={report?.reportID}
shiftVertical={emojiShiftVertical}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/report/ReportActionItemMessageEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,8 @@ function ReportActionItemMessageEdit(
}}
onBlur={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
setIsFocused(false);
// @ts-expect-error TODO: TextInputFocusEventData doesn't contain relatedTarget.
const relatedTargetId = event.nativeEvent?.relatedTarget?.id;
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
if ((relatedTargetId && [messageEditInput, emojiButtonID].includes(relatedTargetId)) || EmojiPickerAction.isEmojiPickerVisible()) {
return;
}
Expand Down
1 change: 0 additions & 1 deletion src/pages/home/report/ReportFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ function ReportFooter({
<View style={[chatFooterStyles, isComposerFullSize && styles.chatFooterFullCompose]}>
<SwipeableView onSwipeDown={Keyboard.dismiss}>
<ReportActionCompose
// @ts-expect-error TODO: Remove this once ReportActionCompose (https://github.com/Expensify/App/issues/31984) is migrated to TypeScript.
onSubmit={onSubmitComment}
onComposerFocus={onComposerFocus}
onComposerBlur={onComposerBlur}
Expand Down
Loading
Loading