diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 6f75cf2eacb6..a8912b2e0f64 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -480,9 +480,9 @@ type OnyxValues = {
     [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction;
     [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.Transaction;
     [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations;
+    [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.Transaction;
     [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags;
     [ONYXKEYS.COLLECTION.SELECTED_TAB]: string;
-    [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolation[];
     [ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string;
     [ONYXKEYS.COLLECTION.NEXT_STEP]: OnyxTypes.ReportNextStep;
 
diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx
index 90954c63b751..78ef72ac3536 100755
--- a/src/components/AttachmentModal.tsx
+++ b/src/components/AttachmentModal.tsx
@@ -283,7 +283,7 @@ function AttachmentModal({
      * Detach the receipt and close the modal.
      */
     const deleteAndCloseModal = useCallback(() => {
-        IOU.detachReceipt(transaction?.transactionID);
+        IOU.detachReceipt(transaction?.transactionID ?? '');
         setIsDeleteReceiptConfirmModalVisible(false);
         Navigation.dismissModal(report?.reportID);
     }, [transaction, report]);
diff --git a/src/components/FormAlertWithSubmitButton.tsx b/src/components/FormAlertWithSubmitButton.tsx
index ae96aa6c5359..789f1cd2466d 100644
--- a/src/components/FormAlertWithSubmitButton.tsx
+++ b/src/components/FormAlertWithSubmitButton.tsx
@@ -7,7 +7,7 @@ import FormAlertWrapper from './FormAlertWrapper';
 
 type FormAlertWithSubmitButtonProps = {
     /** Error message to display above button */
-    message?: string;
+    message?: string | null;
 
     /** Whether the button is disabled */
     isDisabled?: boolean;
diff --git a/src/components/FormAlertWrapper.tsx b/src/components/FormAlertWrapper.tsx
index 65fa2311620d..bdd5622f7aeb 100644
--- a/src/components/FormAlertWrapper.tsx
+++ b/src/components/FormAlertWrapper.tsx
@@ -28,7 +28,7 @@ type FormAlertWrapperProps = {
     isMessageHtml?: boolean;
 
     /** Error message to display above button */
-    message?: string;
+    message?: string | null;
 
     /** Props to detect online status */
     network: Network;
diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx
index 2fad21fb54ef..975d154b885b 100644
--- a/src/components/OfflineWithFeedback.tsx
+++ b/src/components/OfflineWithFeedback.tsx
@@ -59,11 +59,6 @@ type OfflineWithFeedbackProps = ChildrenProps & {
 
 type StrikethroughProps = Partial<ChildrenProps> & {style: Array<ViewStyle | TextStyle | ImageStyle>};
 
-function omitBy<T>(obj: Record<string, T> | undefined | null, predicate: (value: T) => boolean) {
-    // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars
-    return Object.fromEntries(Object.entries(obj ?? {}).filter(([_, value]) => !predicate(value)));
-}
-
 function OfflineWithFeedback({
     pendingAction,
     canDismissError = true,
@@ -84,8 +79,12 @@ function OfflineWithFeedback({
     const {isOffline} = useNetwork();
 
     const hasErrors = !isEmptyObject(errors ?? {});
+
     // Some errors have a null message. This is used to apply opacity only and to avoid showing redundant messages.
-    const errorMessages = omitBy(errors, (e: string | ReceiptError) => e === null);
+    const errorEntries = Object.entries(errors ?? {});
+    const filteredErrorEntries = errorEntries.filter((errorEntry): errorEntry is [string, string | ReceiptError] => errorEntry[1] !== null);
+    const errorMessages = Object.fromEntries(filteredErrorEntries);
+
     const hasErrorMessages = !isEmptyObject(errorMessages);
     const isOfflinePendingAction = !!isOffline && !!pendingAction;
     const isUpdateOrDeleteError = hasErrors && (pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE);
diff --git a/src/components/TextInput/BaseTextInput/index.native.tsx b/src/components/TextInput/BaseTextInput/index.native.tsx
index c9b46ac0b6cb..6f00f06c4c5e 100644
--- a/src/components/TextInput/BaseTextInput/index.native.tsx
+++ b/src/components/TextInput/BaseTextInput/index.native.tsx
@@ -249,6 +249,8 @@ function BaseTextInput(
 
     const hasLabel = Boolean(label?.length);
     const isReadOnly = inputProps.readOnly ?? inputProps.disabled;
+    // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null, and errorText can be an empty string
+    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
     const inputHelpText = errorText || hint;
     const placeholderValue = !!prefixCharacter || isFocused || !hasLabel || (hasLabel && forceActiveLabel) ? placeholder : undefined;
     const maxHeight = StyleSheet.flatten(containerStyles)?.maxHeight;
diff --git a/src/components/TextInput/BaseTextInput/index.tsx b/src/components/TextInput/BaseTextInput/index.tsx
index 90412a37d7a0..800eff15d242 100644
--- a/src/components/TextInput/BaseTextInput/index.tsx
+++ b/src/components/TextInput/BaseTextInput/index.tsx
@@ -244,6 +244,8 @@ function BaseTextInput(
 
     const hasLabel = Boolean(label?.length);
     const isReadOnly = inputProps.readOnly ?? inputProps.disabled;
+    // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null, and errorText can be an empty string
+    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
     const inputHelpText = errorText || hint;
     const newPlaceholder = !!prefixCharacter || isFocused || !hasLabel || (hasLabel && forceActiveLabel) ? placeholder : undefined;
     const maxHeight = StyleSheet.flatten(containerStyles).maxHeight;
diff --git a/src/libs/API/parameters/ApproveMoneyRequestParams.ts b/src/libs/API/parameters/ApproveMoneyRequestParams.ts
new file mode 100644
index 000000000000..f35ff31702d6
--- /dev/null
+++ b/src/libs/API/parameters/ApproveMoneyRequestParams.ts
@@ -0,0 +1,6 @@
+type ApproveMoneyRequestParams = {
+    reportID: string;
+    approvedReportActionID: string;
+};
+
+export default ApproveMoneyRequestParams;
diff --git a/src/libs/API/parameters/CompleteSplitBillParams.ts b/src/libs/API/parameters/CompleteSplitBillParams.ts
new file mode 100644
index 000000000000..50054ba6fd10
--- /dev/null
+++ b/src/libs/API/parameters/CompleteSplitBillParams.ts
@@ -0,0 +1,13 @@
+type CompleteSplitBillParams = {
+    transactionID: string;
+    amount?: number;
+    currency?: string;
+    created?: string;
+    merchant?: string;
+    comment?: string;
+    category?: string;
+    tag?: string;
+    splits: string;
+};
+
+export default CompleteSplitBillParams;
diff --git a/src/libs/API/parameters/CreateDistanceRequestParams.ts b/src/libs/API/parameters/CreateDistanceRequestParams.ts
new file mode 100644
index 000000000000..c1eb1003a698
--- /dev/null
+++ b/src/libs/API/parameters/CreateDistanceRequestParams.ts
@@ -0,0 +1,17 @@
+type CreateDistanceRequestParams = {
+    comment: string;
+    iouReportID: string;
+    chatReportID: string;
+    transactionID: string;
+    reportActionID: string;
+    createdChatReportActionID: string;
+    createdIOUReportActionID: string;
+    reportPreviewReportActionID: string;
+    waypoints: string;
+    created: string;
+    category?: string;
+    tag?: string;
+    billable?: boolean;
+};
+
+export default CreateDistanceRequestParams;
diff --git a/src/libs/API/parameters/DeleteMoneyRequestParams.ts b/src/libs/API/parameters/DeleteMoneyRequestParams.ts
new file mode 100644
index 000000000000..6e7fe30811c4
--- /dev/null
+++ b/src/libs/API/parameters/DeleteMoneyRequestParams.ts
@@ -0,0 +1,6 @@
+type DeleteMoneyRequestParams = {
+    transactionID: string;
+    reportActionID: string;
+};
+
+export default DeleteMoneyRequestParams;
diff --git a/src/libs/API/parameters/DetachReceiptParams.ts b/src/libs/API/parameters/DetachReceiptParams.ts
new file mode 100644
index 000000000000..a19b525a0ef0
--- /dev/null
+++ b/src/libs/API/parameters/DetachReceiptParams.ts
@@ -0,0 +1,5 @@
+type DetachReceiptParams = {
+    transactionID: string;
+};
+
+export default DetachReceiptParams;
diff --git a/src/libs/API/parameters/EditMoneyRequestParams.ts b/src/libs/API/parameters/EditMoneyRequestParams.ts
new file mode 100644
index 000000000000..6d320510e267
--- /dev/null
+++ b/src/libs/API/parameters/EditMoneyRequestParams.ts
@@ -0,0 +1,14 @@
+type EditMoneyRequestParams = {
+    transactionID: string;
+    reportActionID: string;
+    created?: string;
+    amount?: number;
+    currency?: string;
+    comment?: string;
+    merchant?: string;
+    category?: string;
+    billable?: boolean;
+    tag?: string;
+};
+
+export default EditMoneyRequestParams;
diff --git a/src/libs/API/parameters/PayMoneyRequestParams.ts b/src/libs/API/parameters/PayMoneyRequestParams.ts
new file mode 100644
index 000000000000..94f62bcca065
--- /dev/null
+++ b/src/libs/API/parameters/PayMoneyRequestParams.ts
@@ -0,0 +1,11 @@
+import type CONST from '@src/CONST';
+import type DeepValueOf from '@src/types/utils/DeepValueOf';
+
+type PayMoneyRequestParams = {
+    iouReportID: string;
+    chatReportID: string;
+    reportActionID: string;
+    paymentMethodType: DeepValueOf<typeof CONST.IOU.PAYMENT_TYPE>;
+};
+
+export default PayMoneyRequestParams;
diff --git a/src/libs/API/parameters/ReplaceReceiptParams.ts b/src/libs/API/parameters/ReplaceReceiptParams.ts
new file mode 100644
index 000000000000..1046c46bc930
--- /dev/null
+++ b/src/libs/API/parameters/ReplaceReceiptParams.ts
@@ -0,0 +1,6 @@
+type ReplaceReceiptParams = {
+    transactionID: string;
+    receipt: File;
+};
+
+export default ReplaceReceiptParams;
diff --git a/src/libs/API/parameters/RequestMoneyParams.ts b/src/libs/API/parameters/RequestMoneyParams.ts
new file mode 100644
index 000000000000..ccafdd692137
--- /dev/null
+++ b/src/libs/API/parameters/RequestMoneyParams.ts
@@ -0,0 +1,29 @@
+import type {ValueOf} from 'type-fest';
+import type CONST from '@src/CONST';
+import type {Receipt} from '@src/types/onyx/Transaction';
+
+type RequestMoneyParams = {
+    debtorEmail: string;
+    debtorAccountID: number;
+    amount: number;
+    currency: string;
+    comment: string;
+    created: string;
+    merchant: string;
+    iouReportID: string;
+    chatReportID: string;
+    transactionID: string;
+    reportActionID: string;
+    createdChatReportActionID: string;
+    createdIOUReportActionID: string;
+    reportPreviewReportActionID: string;
+    receipt: Receipt;
+    receiptState?: ValueOf<typeof CONST.IOU.RECEIPT_STATE>;
+    category?: string;
+    tag?: string;
+    taxCode: string;
+    taxAmount: number;
+    billable?: boolean;
+};
+
+export default RequestMoneyParams;
diff --git a/src/libs/API/parameters/SendMoneyParams.ts b/src/libs/API/parameters/SendMoneyParams.ts
new file mode 100644
index 000000000000..c32287d5b4ec
--- /dev/null
+++ b/src/libs/API/parameters/SendMoneyParams.ts
@@ -0,0 +1,15 @@
+import type CONST from '@src/CONST';
+import type DeepValueOf from '@src/types/utils/DeepValueOf';
+
+type SendMoneyParams = {
+    iouReportID: string;
+    chatReportID: string;
+    reportActionID: string;
+    paymentMethodType: DeepValueOf<typeof CONST.IOU.PAYMENT_TYPE>;
+    transactionID: string;
+    newIOUReportDetails: string;
+    createdReportActionID: string;
+    reportPreviewReportActionID: string;
+};
+
+export default SendMoneyParams;
diff --git a/src/libs/API/parameters/SplitBillParams.ts b/src/libs/API/parameters/SplitBillParams.ts
new file mode 100644
index 000000000000..23d4ff3d6d78
--- /dev/null
+++ b/src/libs/API/parameters/SplitBillParams.ts
@@ -0,0 +1,17 @@
+type SplitBillParams = {
+    reportID: string;
+    amount: number;
+    splits: string;
+    comment: string;
+    currency: string;
+    merchant: string;
+    category: string;
+    tag: string;
+    billable: boolean;
+    transactionID: string;
+    reportActionID: string;
+    createdReportActionID?: string;
+    policyID?: string;
+};
+
+export default SplitBillParams;
diff --git a/src/libs/API/parameters/StartSplitBillParams.ts b/src/libs/API/parameters/StartSplitBillParams.ts
new file mode 100644
index 000000000000..30d21697ac67
--- /dev/null
+++ b/src/libs/API/parameters/StartSplitBillParams.ts
@@ -0,0 +1,17 @@
+import type {Receipt} from '@src/types/onyx/Transaction';
+
+type StartSplitBillParams = {
+    chatReportID: string;
+    reportActionID: string;
+    transactionID: string;
+    splits: string;
+    receipt: Receipt;
+    comment: string;
+    category: string;
+    tag: string;
+    isFromGroupDM: boolean;
+    createdReportActionID?: string;
+    billable: boolean;
+};
+
+export default StartSplitBillParams;
diff --git a/src/libs/API/parameters/SubmitReportParams.ts b/src/libs/API/parameters/SubmitReportParams.ts
new file mode 100644
index 000000000000..0132344aab6c
--- /dev/null
+++ b/src/libs/API/parameters/SubmitReportParams.ts
@@ -0,0 +1,7 @@
+type SubmitReportParams = {
+    reportID: string;
+    managerAccountID?: number;
+    reportActionID: string;
+};
+
+export default SubmitReportParams;
diff --git a/src/libs/API/parameters/UpdateMoneyRequestParams.ts b/src/libs/API/parameters/UpdateMoneyRequestParams.ts
new file mode 100644
index 000000000000..549d02260beb
--- /dev/null
+++ b/src/libs/API/parameters/UpdateMoneyRequestParams.ts
@@ -0,0 +1,9 @@
+import type {TransactionDetails} from '@libs/ReportUtils';
+
+type UpdateMoneyRequestParams = Partial<TransactionDetails> & {
+    reportID?: string;
+    transactionID: string;
+    reportActionID?: string;
+};
+
+export default UpdateMoneyRequestParams;
diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts
index 8103b54f8d81..4d784463c2f8 100644
--- a/src/libs/API/parameters/index.ts
+++ b/src/libs/API/parameters/index.ts
@@ -125,3 +125,17 @@ export type {default as CompleteEngagementModalParams} from './CompleteEngagemen
 export type {default as SetNameValuePairParams} from './SetNameValuePairParams';
 export type {default as SetReportFieldParams} from './SetReportFieldParams';
 export type {default as SetReportNameParams} from './SetReportNameParams';
+export type {default as CompleteSplitBillParams} from './CompleteSplitBillParams';
+export type {default as UpdateMoneyRequestParams} from './UpdateMoneyRequestParams';
+export type {default as RequestMoneyParams} from './RequestMoneyParams';
+export type {default as SplitBillParams} from './SplitBillParams';
+export type {default as DeleteMoneyRequestParams} from './DeleteMoneyRequestParams';
+export type {default as CreateDistanceRequestParams} from './CreateDistanceRequestParams';
+export type {default as StartSplitBillParams} from './StartSplitBillParams';
+export type {default as SendMoneyParams} from './SendMoneyParams';
+export type {default as ApproveMoneyRequestParams} from './ApproveMoneyRequestParams';
+export type {default as EditMoneyRequestParams} from './EditMoneyRequestParams';
+export type {default as ReplaceReceiptParams} from './ReplaceReceiptParams';
+export type {default as SubmitReportParams} from './SubmitReportParams';
+export type {default as DetachReceiptParams} from './DetachReceiptParams';
+export type {default as PayMoneyRequestParams} from './PayMoneyRequestParams';
diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts
index 7e6a8a8e3f13..a4ab3db9a7cd 100644
--- a/src/libs/API/types.ts
+++ b/src/libs/API/types.ts
@@ -116,6 +116,31 @@ const WRITE_COMMANDS = {
     SET_NAME_VALUE_PAIR: 'SetNameValuePair',
     SET_REPORT_FIELD: 'Report_SetFields',
     SET_REPORT_NAME: 'RenameReport',
+    COMPLETE_SPLIT_BILL: 'CompleteSplitBill',
+    UPDATE_MONEY_REQUEST_DATE: 'UpdateMoneyRequestDate',
+    UPDATE_MONEY_REQUEST_BILLABLE: 'UpdateMoneyRequestBillable',
+    UPDATE_MONEY_REQUEST_MERCHANT: 'UpdateMoneyRequestMerchant',
+    UPDATE_MONEY_REQUEST_TAG: 'UpdateMoneyRequestTag',
+    UPDATE_MONEY_REQUEST_DISTANCE: 'UpdateMoneyRequestDistance',
+    UPDATE_MONEY_REQUEST_CATEGORY: 'UpdateMoneyRequestCategory',
+    UPDATE_MONEY_REQUEST_DESCRIPTION: 'UpdateMoneyRequestDescription',
+    UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY: 'UpdateMoneyRequestAmountAndCurrency',
+    UPDATE_DISTANCE_REQUEST: 'UpdateDistanceRequest',
+    REQUEST_MONEY: 'RequestMoney',
+    SPLIT_BILL: 'SplitBill',
+    SPLIT_BILL_AND_OPEN_REPORT: 'SplitBillAndOpenReport',
+    DELETE_MONEY_REQUEST: 'DeleteMoneyRequest',
+    CREATE_DISTANCE_REQUEST: 'CreateDistanceRequest',
+    START_SPLIT_BILL: 'StartSplitBill',
+    SEND_MONEY_ELSEWHERE: 'SendMoneyElsewhere',
+    SEND_MONEY_WITH_WALLET: 'SendMoneyWithWallet',
+    APPROVE_MONEY_REQUEST: 'ApproveMoneyRequest',
+    EDIT_MONEY_REQUEST: 'EditMoneyRequest',
+    REPLACE_RECEIPT: 'ReplaceReceipt',
+    SUBMIT_REPORT: 'SubmitReport',
+    DETACH_RECEIPT: 'DetachReceipt',
+    PAY_MONEY_REQUEST_WITH_WALLET: 'PayMoneyRequestWithWallet',
+    PAY_MONEY_REQUEST: 'PayMoneyRequest',
 } as const;
 
 type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;
@@ -229,6 +254,31 @@ type WriteCommandParameters = {
     [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams;
     [WRITE_COMMANDS.SET_REPORT_FIELD]: Parameters.SetReportFieldParams;
     [WRITE_COMMANDS.SET_REPORT_NAME]: Parameters.SetReportNameParams;
+    [WRITE_COMMANDS.COMPLETE_SPLIT_BILL]: Parameters.CompleteSplitBillParams;
+    [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DATE]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_MERCHANT]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_BILLABLE]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_TAG]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DISTANCE]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_CATEGORY]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DESCRIPTION]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.UPDATE_DISTANCE_REQUEST]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY]: Parameters.UpdateMoneyRequestParams;
+    [WRITE_COMMANDS.REQUEST_MONEY]: Parameters.RequestMoneyParams;
+    [WRITE_COMMANDS.SPLIT_BILL]: Parameters.SplitBillParams;
+    [WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT]: Parameters.SplitBillParams;
+    [WRITE_COMMANDS.DELETE_MONEY_REQUEST]: Parameters.DeleteMoneyRequestParams;
+    [WRITE_COMMANDS.CREATE_DISTANCE_REQUEST]: Parameters.CreateDistanceRequestParams;
+    [WRITE_COMMANDS.START_SPLIT_BILL]: Parameters.StartSplitBillParams;
+    [WRITE_COMMANDS.SEND_MONEY_ELSEWHERE]: Parameters.SendMoneyParams;
+    [WRITE_COMMANDS.SEND_MONEY_WITH_WALLET]: Parameters.SendMoneyParams;
+    [WRITE_COMMANDS.APPROVE_MONEY_REQUEST]: Parameters.ApproveMoneyRequestParams;
+    [WRITE_COMMANDS.EDIT_MONEY_REQUEST]: Parameters.EditMoneyRequestParams;
+    [WRITE_COMMANDS.REPLACE_RECEIPT]: Parameters.ReplaceReceiptParams;
+    [WRITE_COMMANDS.SUBMIT_REPORT]: Parameters.SubmitReportParams;
+    [WRITE_COMMANDS.DETACH_RECEIPT]: Parameters.DetachReceiptParams;
+    [WRITE_COMMANDS.PAY_MONEY_REQUEST_WITH_WALLET]: Parameters.PayMoneyRequestParams;
+    [WRITE_COMMANDS.PAY_MONEY_REQUEST]: Parameters.PayMoneyRequestParams;
 };
 
 const READ_COMMANDS = {
diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts
index 6298138a5825..6fbba1e750dc 100644
--- a/src/libs/ErrorUtils.ts
+++ b/src/libs/ErrorUtils.ts
@@ -38,7 +38,7 @@ function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatO
  * Method used to get an error object with microsecond as the key.
  * @param error - error key or message to be saved
  */
-function getMicroSecondOnyxError(error: string): Errors {
+function getMicroSecondOnyxError(error: string | null): Errors {
     return {[DateUtils.getMicroseconds()]: error};
 }
 
@@ -46,7 +46,7 @@ function getMicroSecondOnyxError(error: string): Errors {
  * Method used to get an error object with microsecond as the key and an object as the value.
  * @param error - error key or message to be saved
  */
-function getMicroSecondOnyxErrorObject(error: Record<string, string>): Record<number, Record<string, string>> {
+function getMicroSecondOnyxErrorObject(error: Errors): ErrorFields {
     return {[DateUtils.getMicroseconds()]: error};
 }
 
@@ -54,7 +54,7 @@ type OnyxDataWithErrors = {
     errors?: Errors | null;
 };
 
-function getLatestErrorMessage<TOnyxData extends OnyxDataWithErrors>(onyxData: TOnyxData): string {
+function getLatestErrorMessage<TOnyxData extends OnyxDataWithErrors>(onyxData: TOnyxData): string | null {
     const errors = onyxData.errors ?? {};
 
     if (Object.keys(errors).length === 0) {
@@ -66,7 +66,7 @@ function getLatestErrorMessage<TOnyxData extends OnyxDataWithErrors>(onyxData: T
     return errors[key];
 }
 
-function getLatestErrorMessageField<TOnyxData extends OnyxDataWithErrors>(onyxData: TOnyxData): Record<string, string> {
+function getLatestErrorMessageField<TOnyxData extends OnyxDataWithErrors>(onyxData: TOnyxData): Errors {
     const errors = onyxData.errors ?? {};
 
     if (Object.keys(errors).length === 0) {
@@ -82,7 +82,7 @@ type OnyxDataWithErrorFields = {
     errorFields?: ErrorFields;
 };
 
-function getLatestErrorField<TOnyxData extends OnyxDataWithErrorFields>(onyxData: TOnyxData, fieldName: string): Record<string, string> {
+function getLatestErrorField<TOnyxData extends OnyxDataWithErrorFields>(onyxData: TOnyxData, fieldName: string): Errors {
     const errorsForField = onyxData.errorFields?.[fieldName] ?? {};
 
     if (Object.keys(errorsForField).length === 0) {
@@ -94,7 +94,7 @@ function getLatestErrorField<TOnyxData extends OnyxDataWithErrorFields>(onyxData
     return {[key]: errorsForField[key]};
 }
 
-function getEarliestErrorField<TOnyxData extends OnyxDataWithErrorFields>(onyxData: TOnyxData, fieldName: string): Record<string, string> {
+function getEarliestErrorField<TOnyxData extends OnyxDataWithErrorFields>(onyxData: TOnyxData, fieldName: string): Errors {
     const errorsForField = onyxData.errorFields?.[fieldName] ?? {};
 
     if (Object.keys(errorsForField).length === 0) {
diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts
index c0fb4c6195b1..d70f4fc08102 100644
--- a/src/libs/IOUUtils.ts
+++ b/src/libs/IOUUtils.ts
@@ -54,13 +54,13 @@ function calculateAmount(numberOfParticipants: number, total: number, currency:
  *
  * @param isDeleting - whether the user is deleting the request
  */
-function updateIOUOwnerAndTotal(iouReport: OnyxEntry<Report>, actorAccountID: number, amount: number, currency: string, isDeleting = false): OnyxEntry<Report> {
+function updateIOUOwnerAndTotal<TReport extends OnyxEntry<Report>>(iouReport: TReport, actorAccountID: number, amount: number, currency: string, isDeleting = false): TReport {
     if (currency !== iouReport?.currency) {
         return iouReport;
     }
 
     // Make a copy so we don't mutate the original object
-    const iouReportUpdate: Report = {...iouReport};
+    const iouReportUpdate = {...iouReport};
 
     // Let us ensure a valid value before updating the total amount.
     iouReportUpdate.total = iouReportUpdate.total ?? 0;
diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts
index 46ca550eaa1a..0df9e25eff25 100644
--- a/src/libs/Localize/index.ts
+++ b/src/libs/Localize/index.ts
@@ -98,7 +98,7 @@ function translateLocal<TKey extends TranslationPaths>(phrase: TKey, ...variable
     return translate(BaseLocaleListener.getPreferredLocale(), phrase, ...variables);
 }
 
-type MaybePhraseKey = string | [string, Record<string, unknown> & {isTranslated?: true}] | [];
+type MaybePhraseKey = string | null | [string, Record<string, unknown> & {isTranslated?: true}] | [];
 
 /**
  * Return translated string for given error.
diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts
index aaae113b7da1..d9e57f5e3bb8 100644
--- a/src/libs/PolicyUtils.ts
+++ b/src/libs/PolicyUtils.ts
@@ -104,7 +104,7 @@ function isExpensifyGuideTeam(email: string): boolean {
 /**
  * Checks if the current user is an admin of the policy.
  */
-const isPolicyAdmin = (policy: OnyxEntry<Policy>): boolean => policy?.role === CONST.POLICY.ROLE.ADMIN;
+const isPolicyAdmin = (policy: OnyxEntry<Policy> | EmptyObject): boolean => policy?.role === CONST.POLICY.ROLE.ADMIN;
 
 const isPolicyMember = (policyID: string, policies: Record<string, Policy>): boolean => Object.values(policies).some((policy) => policy?.id === policyID);
 
@@ -200,7 +200,7 @@ function isPendingDeletePolicy(policy: OnyxEntry<Policy>): boolean {
     return policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
 }
 
-function isPaidGroupPolicy(policy: OnyxEntry<Policy>): boolean {
+function isPaidGroupPolicy(policy: OnyxEntry<Policy> | EmptyObject): boolean {
     return policy?.type === CONST.POLICY.TYPE.TEAM || policy?.type === CONST.POLICY.TYPE.CORPORATE;
 }
 
diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts
index 948d8094d551..f31a1aa811a0 100644
--- a/src/libs/ReceiptUtils.ts
+++ b/src/libs/ReceiptUtils.ts
@@ -50,7 +50,7 @@ function getThumbnailAndImageURIs(transaction: OnyxEntry<Transaction>, receiptPa
     }
 
     // For local files, we won't have a thumbnail yet
-    if (isReceiptImage && (path.startsWith('blob:') || path.startsWith('file:'))) {
+    if (isReceiptImage && typeof path === 'string' && (path.startsWith('blob:') || path.startsWith('file:'))) {
         return {thumbnail: null, image: path, isLocalFile: true, filename};
     }
 
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index 6e7cd0cdd999..1aeb6e6e7343 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -432,9 +432,9 @@ function replaceBaseURLInPolicyChangeLogAction(reportAction: ReportAction): Repo
     return updatedReportAction;
 }
 
-function getLastVisibleAction(reportID: string, actionsToMerge: ReportActions = {}): OnyxEntry<ReportAction> {
-    const reportActions = Object.values(fastMerge(allReportActions?.[reportID] ?? {}, actionsToMerge, true));
-    const visibleReportActions = Object.values(reportActions ?? {}).filter((action) => shouldReportActionBeVisibleAsLastAction(action));
+function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection<ReportAction> = {}): OnyxEntry<ReportAction> {
+    const reportActions = Object.values(fastMerge(allReportActions?.[reportID] ?? {}, actionsToMerge ?? {}, true));
+    const visibleReportActions = Object.values(reportActions ?? {}).filter((action): action is ReportAction => shouldReportActionBeVisibleAsLastAction(action));
     const sortedReportActions = getSortedReportActions(visibleReportActions, true);
     if (sortedReportActions.length === 0) {
         return null;
@@ -442,7 +442,7 @@ function getLastVisibleAction(reportID: string, actionsToMerge: ReportActions =
     return sortedReportActions[0];
 }
 
-function getLastVisibleMessage(reportID: string, actionsToMerge: ReportActions = {}): LastVisibleMessage {
+function getLastVisibleMessage(reportID: string, actionsToMerge: OnyxCollection<ReportAction> = {}): LastVisibleMessage {
     const lastVisibleAction = getLastVisibleAction(reportID, actionsToMerge);
     const message = lastVisibleAction?.message?.[0];
 
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 75503bfed11d..5c6672d14bd7 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -34,7 +34,7 @@ import type {ChangeLog, IOUMessage, OriginalMessageActionName, OriginalMessageCr
 import type {Status} from '@src/types/onyx/PersonalDetails';
 import type {NotificationPreference} from '@src/types/onyx/Report';
 import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction';
-import type {Receipt, WaypointCollection} from '@src/types/onyx/Transaction';
+import type {Receipt, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
 import type {EmptyObject} from '@src/types/utils/EmptyObject';
 import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import type IconAsset from '@src/types/utils/IconAsset';
@@ -165,27 +165,6 @@ type OptimisticIOUReportAction = Pick<
     | 'whisperedToAccountIDs'
 >;
 
-type OptimisticReportPreview = Pick<
-    ReportAction,
-    | 'actionName'
-    | 'reportActionID'
-    | 'pendingAction'
-    | 'originalMessage'
-    | 'message'
-    | 'created'
-    | 'actorAccountID'
-    | 'childMoneyRequestCount'
-    | 'childLastMoneyRequestComment'
-    | 'childRecentReceiptTransactionIDs'
-    | 'childReportID'
-    | 'whisperedToAccountIDs'
-> & {reportID?: string; accountID?: number};
-
-type UpdateReportPreview = Pick<
-    ReportAction,
-    'created' | 'message' | 'childLastMoneyRequestComment' | 'childMoneyRequestCount' | 'childRecentReceiptTransactionIDs' | 'whisperedToAccountIDs'
->;
-
 type ReportRouteParams = {
     reportID: string;
     isSubReportPageRoute: boolean;
@@ -193,7 +172,7 @@ type ReportRouteParams = {
 
 type ReportOfflinePendingActionAndErrors = {
     addWorkspaceRoomOrChatPendingAction: PendingAction | undefined;
-    addWorkspaceRoomOrChatErrors: Record<string, string> | null | undefined;
+    addWorkspaceRoomOrChatErrors: Errors | null | undefined;
 };
 
 type OptimisticApprovedReportAction = Pick<
@@ -223,6 +202,8 @@ type OptimisticChatReport = Pick<
     Report,
     | 'type'
     | 'chatType'
+    | 'chatReportID'
+    | 'iouReportID'
     | 'isOwnPolicyExpenseChat'
     | 'isPinned'
     | 'lastActorAccountID'
@@ -234,6 +215,7 @@ type OptimisticChatReport = Pick<
     | 'notificationPreference'
     | 'oldPolicyName'
     | 'ownerAccountID'
+    | 'pendingFields'
     | 'parentReportActionID'
     | 'parentReportID'
     | 'participantAccountIDs'
@@ -307,23 +289,21 @@ type OptimisticTaskReport = Pick<
     | 'lastVisibleActionCreated'
 >;
 
-type TransactionDetails =
-    | {
-          created: string;
-          amount: number;
-          currency: string;
-          merchant: string;
-          waypoints?: WaypointCollection;
-          comment: string;
-          category: string;
-          billable: boolean;
-          tag: string;
-          mccGroup?: ValueOf<typeof CONST.MCC_GROUPS>;
-          cardID: number;
-          originalAmount: number;
-          originalCurrency: string;
-      }
-    | undefined;
+type TransactionDetails = {
+    created: string;
+    amount: number;
+    currency: string;
+    merchant: string;
+    waypoints?: WaypointCollection | string;
+    comment: string;
+    category: string;
+    billable: boolean;
+    tag: string;
+    mccGroup?: ValueOf<typeof CONST.MCC_GROUPS>;
+    cardID: number;
+    originalAmount: number;
+    originalCurrency: string;
+};
 
 type OptimisticIOUReport = Pick<
     Report,
@@ -332,6 +312,7 @@ type OptimisticIOUReport = Pick<
     | 'chatReportID'
     | 'currency'
     | 'managerID'
+    | 'policyID'
     | 'ownerAccountID'
     | 'participantAccountIDs'
     | 'visibleChatMemberAccountIDs'
@@ -503,7 +484,7 @@ Onyx.connect({
     },
 });
 
-function getChatType(report: OnyxEntry<Report>): ValueOf<typeof CONST.REPORT.CHAT_TYPE> | undefined {
+function getChatType(report: OnyxEntry<Report> | Participant | EmptyObject): ValueOf<typeof CONST.REPORT.CHAT_TYPE> | undefined {
     return report?.chatType;
 }
 
@@ -552,7 +533,7 @@ function getRootParentReport(report: OnyxEntry<Report> | undefined | EmptyObject
     return getRootParentReport(!isEmptyObject(parentReport) ? parentReport : null);
 }
 
-function getPolicy(policyID: string): Policy | EmptyObject {
+function getPolicy(policyID: string | undefined): Policy | EmptyObject {
     if (!allPolicies || !policyID) {
         return {};
     }
@@ -783,7 +764,7 @@ function isUserCreatedPolicyRoom(report: OnyxEntry<Report>): boolean {
 /**
  * Whether the provided report is a Policy Expense chat.
  */
-function isPolicyExpenseChat(report: OnyxEntry<Report>): boolean {
+function isPolicyExpenseChat(report: OnyxEntry<Report> | Participant | EmptyObject): boolean {
     return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false);
 }
 
@@ -1995,7 +1976,7 @@ function getMoneyRequestReportName(report: OnyxEntry<Report>, policy: OnyxEntry<
  * into a flat object. Used for displaying transactions and sending them in API commands
  */
 
-function getTransactionDetails(transaction: OnyxEntry<Transaction>, createdDateFormat: string = CONST.DATE.FNS_FORMAT_STRING): TransactionDetails {
+function getTransactionDetails(transaction: OnyxEntry<Transaction>, createdDateFormat: string = CONST.DATE.FNS_FORMAT_STRING): TransactionDetails | undefined {
     if (!transaction) {
         return;
     }
@@ -2326,7 +2307,7 @@ function getReportPreviewMessage(
  *
  * At the moment, we only allow changing one transaction field at a time.
  */
-function getModifiedExpenseOriginalMessage(oldTransaction: OnyxEntry<Transaction>, transactionChanges: ExpenseOriginalMessage, isFromExpenseReport: boolean): ExpenseOriginalMessage {
+function getModifiedExpenseOriginalMessage(oldTransaction: OnyxEntry<Transaction>, transactionChanges: TransactionChanges, isFromExpenseReport: boolean): ExpenseOriginalMessage {
     const originalMessage: ExpenseOriginalMessage = {};
     // Remark: Comment field is the only one which has new/old prefixes for the keys (newComment/ oldComment),
     // all others have old/- pattern such as oldCreated/created
@@ -2933,7 +2914,7 @@ function buildOptimisticIOUReportAction(
     comment: string,
     participants: Participant[],
     transactionID: string,
-    paymentType: PaymentMethodType,
+    paymentType?: PaymentMethodType,
     iouReportID = '',
     isSettlingUp = false,
     isSendMoneyFlow = false,
@@ -2978,8 +2959,8 @@ function buildOptimisticIOUReportAction(
             originalMessage.participantAccountIDs = currentUserAccountID ? [currentUserAccountID] : [];
         } else {
             originalMessage.participantAccountIDs = currentUserAccountID
-                ? [currentUserAccountID, ...participants.map((participant) => participant.accountID)]
-                : participants.map((participant) => participant.accountID);
+                ? [currentUserAccountID, ...participants.map((participant) => participant.accountID ?? -1)]
+                : participants.map((participant) => participant.accountID ?? -1);
         }
     }
 
@@ -3121,13 +3102,7 @@ function buildOptimisticSubmittedReportAction(amount: number, currency: string,
  * @param [comment] - User comment for the IOU.
  * @param [transaction] - optimistic first transaction of preview
  */
-function buildOptimisticReportPreview(
-    chatReport: OnyxEntry<Report>,
-    iouReport: OnyxEntry<Report>,
-    comment = '',
-    transaction: OnyxEntry<Transaction> = null,
-    childReportID?: string,
-): OptimisticReportPreview {
+function buildOptimisticReportPreview(chatReport: OnyxEntry<Report>, iouReport: Report, comment = '', transaction: OnyxEntry<Transaction> = null, childReportID?: string): ReportAction {
     const hasReceipt = TransactionUtils.hasReceipt(transaction);
     const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction);
     const message = getReportPreviewMessage(iouReport);
@@ -3164,9 +3139,9 @@ function buildOptimisticReportPreview(
  * Builds an optimistic modified expense action with a randomly generated reportActionID.
  */
 function buildOptimisticModifiedExpenseReportAction(
-    transactionThread: OnyxEntry<Transaction>,
+    transactionThread: OnyxEntry<Report>,
     oldTransaction: OnyxEntry<Transaction>,
-    transactionChanges: ExpenseOriginalMessage,
+    transactionChanges: TransactionChanges,
     isFromExpenseReport: boolean,
 ): OptimisticModifiedExpenseReportAction {
     const originalMessage = getModifiedExpenseOriginalMessage(oldTransaction, transactionChanges, isFromExpenseReport);
@@ -3207,13 +3182,7 @@ function buildOptimisticModifiedExpenseReportAction(
  * @param [transaction] - optimistic newest transaction of a report preview
  *
  */
-function updateReportPreview(
-    iouReport: OnyxEntry<Report>,
-    reportPreviewAction: OnyxEntry<ReportAction>,
-    isPayRequest = false,
-    comment = '',
-    transaction: OnyxEntry<Transaction> = null,
-): UpdateReportPreview {
+function updateReportPreview(iouReport: OnyxEntry<Report>, reportPreviewAction: ReportAction, isPayRequest = false, comment = '', transaction: OnyxEntry<Transaction> = null): ReportAction {
     const hasReceipt = TransactionUtils.hasReceipt(transaction);
     const recentReceiptTransactions = reportPreviewAction?.childRecentReceiptTransactionIDs ?? {};
     const transactionsToKeep = TransactionUtils.getRecentTransactions(recentReceiptTransactions);
@@ -4209,7 +4178,7 @@ function isValidReportIDFromPath(reportIDFromPath: string): boolean {
 /**
  * Return the errors we have when creating a chat or a workspace room
  */
-function getAddWorkspaceRoomOrChatReportErrors(report: OnyxEntry<Report>): Record<string, string> | null | undefined {
+function getAddWorkspaceRoomOrChatReportErrors(report: OnyxEntry<Report>): Errors | null | undefined {
     // We are either adding a workspace room, or we're creating a chat, it isn't possible for both of these to have errors for the same report at the same time, so
     // simply looking up the first truthy value will get the relevant property if it's set.
     return report?.errorFields?.addWorkspaceRoom ?? report?.errorFields?.createChat;
@@ -4994,4 +4963,6 @@ export type {
     OptimisticCreatedReportAction,
     OptimisticClosedReportAction,
     Ancestor,
+    OptimisticIOUReportAction,
+    TransactionDetails,
 };
diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts
index 8e48eddea0ac..8a814f311481 100644
--- a/src/libs/TransactionUtils.ts
+++ b/src/libs/TransactionUtils.ts
@@ -6,16 +6,12 @@ import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {RecentWaypoint, Report, ReportAction, Transaction, TransactionViolation} from '@src/types/onyx';
 import type {PolicyTaxRate, PolicyTaxRates} from '@src/types/onyx/PolicyTaxRates';
-import type {Comment, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction';
+import type {Comment, Receipt, TransactionChanges, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction';
 import type {EmptyObject} from '@src/types/utils/EmptyObject';
 import {isCorporateCard, isExpensifyCard} from './CardUtils';
 import DateUtils from './DateUtils';
 import * as NumberUtils from './NumberUtils';
 
-type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection};
-
-type TransactionChanges = Partial<Transaction> & AdditionalTransactionChanges;
-
 let allTransactions: OnyxCollection<Transaction> = {};
 
 Onyx.connect({
diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts
index b3e733d1f6b3..7ee7d6c4f048 100644
--- a/src/libs/ValidationUtils.ts
+++ b/src/libs/ValidationUtils.ts
@@ -75,7 +75,7 @@ function isValidPastDate(date: string | Date): boolean {
 /**
  * Used to validate a value that is "required".
  */
-function isRequiredFulfilled(value: string | Date | unknown[] | Record<string, unknown>): boolean {
+function isRequiredFulfilled(value: string | Date | unknown[] | Record<string, unknown> | null): boolean {
     if (typeof value === 'string') {
         return !StringUtils.isEmptyString(value);
     }
diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts
index c0558d7487cf..9a05ba4d87ed 100644
--- a/src/libs/Violations/ViolationsUtils.ts
+++ b/src/libs/Violations/ViolationsUtils.ts
@@ -1,5 +1,6 @@
 import reject from 'lodash/reject';
 import Onyx from 'react-native-onyx';
+import type {OnyxUpdate} from 'react-native-onyx';
 import type {Phrase, PhraseParameters} from '@libs/Localize';
 import type {TranslationPaths} from '@src/languages/types';
 import ONYXKEYS from '@src/ONYXKEYS';
@@ -17,17 +18,13 @@ const ViolationsUtils = {
         policyTags: PolicyTags,
         policyRequiresCategories: boolean,
         policyCategories: PolicyCategories,
-    ): {
-        onyxMethod: string;
-        key: string;
-        value: TransactionViolation[];
-    } {
+    ): OnyxUpdate {
         let newTransactionViolations = [...transactionViolations];
 
         if (policyRequiresCategories) {
             const hasCategoryOutOfPolicyViolation = transactionViolations.some((violation) => violation.name === 'categoryOutOfPolicy');
             const hasMissingCategoryViolation = transactionViolations.some((violation) => violation.name === 'missingCategory');
-            const isCategoryInPolicy = Boolean(policyCategories[transaction.category]?.enabled);
+            const isCategoryInPolicy = !!policyCategories[transaction.category ?? '']?.enabled;
 
             // Add 'categoryOutOfPolicy' violation if category is not in policy
             if (!hasCategoryOutOfPolicyViolation && transaction.category && !isCategoryInPolicy) {
@@ -53,7 +50,7 @@ const ViolationsUtils = {
         if (policyRequiresTags) {
             const hasTagOutOfPolicyViolation = transactionViolations.some((violation) => violation.name === 'tagOutOfPolicy');
             const hasMissingTagViolation = transactionViolations.some((violation) => violation.name === 'missingTag');
-            const isTagInPolicy = Boolean(policyTags[transaction.tag]?.enabled);
+            const isTagInPolicy = !!policyTags[transaction.tag ?? '']?.enabled;
 
             // Add 'tagOutOfPolicy' violation if tag is not in policy
             if (!hasTagOutOfPolicyViolation && transaction.tag && !isTagInPolicy) {
@@ -155,7 +152,7 @@ const ViolationsUtils = {
                     brokenBankConnection: violation.data?.brokenBankConnection ?? false,
                     isAdmin: violation.data?.isAdmin ?? false,
                     email: violation.data?.email,
-                    isTransactionOlderThan7Days: Boolean(violation.data?.isTransactionOlderThan7Days),
+                    isTransactionOlderThan7Days: !!violation.data?.isTransactionOlderThan7Days,
                     member: violation.data?.member,
                 });
             case 'smartscanFailed':
diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.ts
similarity index 63%
rename from src/libs/actions/IOU.js
rename to src/libs/actions/IOU.ts
index 7da6e13d1f86..569b6b26b728 100644
--- a/src/libs/actions/IOU.js
+++ b/src/libs/actions/IOU.ts
@@ -1,12 +1,29 @@
+import type {StackScreenProps} from '@react-navigation/stack';
 import {format} from 'date-fns';
 import fastMerge from 'expensify-common/lib/fastMerge';
 import Str from 'expensify-common/lib/str';
-import lodashGet from 'lodash/get';
-import lodashHas from 'lodash/has';
 import Onyx from 'react-native-onyx';
-import _ from 'underscore';
+import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
+import type {ValueOf} from 'type-fest';
 import ReceiptGeneric from '@assets/images/receipt-generic.png';
 import * as API from '@libs/API';
+import type {
+    ApproveMoneyRequestParams,
+    CompleteSplitBillParams,
+    CreateDistanceRequestParams,
+    DeleteMoneyRequestParams,
+    DetachReceiptParams,
+    EditMoneyRequestParams,
+    PayMoneyRequestParams,
+    ReplaceReceiptParams,
+    RequestMoneyParams,
+    SendMoneyParams,
+    SplitBillParams,
+    StartSplitBillParams,
+    SubmitReportParams,
+    UpdateMoneyRequestParams,
+} from '@libs/API/parameters';
+import {WRITE_COMMANDS} from '@libs/API/types';
 import * as CurrencyUtils from '@libs/CurrencyUtils';
 import DateUtils from '@libs/DateUtils';
 import * as ErrorUtils from '@libs/ErrorUtils';
@@ -21,128 +38,200 @@ import Permissions from '@libs/Permissions';
 import * as PolicyUtils from '@libs/PolicyUtils';
 import * as ReportActionsUtils from '@libs/ReportActionsUtils';
 import * as ReportUtils from '@libs/ReportUtils';
+import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, TransactionDetails} from '@libs/ReportUtils';
 import * as TransactionUtils from '@libs/TransactionUtils';
 import * as UserUtils from '@libs/UserUtils';
 import ViolationsUtils from '@libs/Violations/ViolationsUtils';
+import type {MoneyRequestNavigatorParamList} from '@navigation/types';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
+import type SCREENS from '@src/SCREENS';
+import type * as OnyxTypes from '@src/types/onyx';
+import type {Participant, Split} from '@src/types/onyx/IOU';
+import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon';
+import type ReportAction from '@src/types/onyx/ReportAction';
+import type {OnyxData} from '@src/types/onyx/Request';
+import type {Comment, Receipt, ReceiptSource, TaxRate, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction';
+import type DeepValueOf from '@src/types/utils/DeepValueOf';
+import type {EmptyObject} from '@src/types/utils/EmptyObject';
+import {isEmptyObject} from '@src/types/utils/EmptyObject';
 import * as Policy from './Policy';
 import * as Report from './Report';
 
-let betas;
+type MoneyRequestRoute = StackScreenProps<MoneyRequestNavigatorParamList, typeof SCREENS.MONEY_REQUEST.CATEGORY | typeof SCREENS.MONEY_REQUEST.CONFIRMATION>['route'];
+
+type IOURequestType = ValueOf<typeof CONST.IOU.REQUEST_TYPE>;
+
+type PaymentMethodType = DeepValueOf<typeof CONST.IOU.PAYMENT_TYPE>;
+
+type OneOnOneIOUReport = OnyxTypes.Report | undefined | null;
+
+type MoneyRequestInformation = {
+    payerAccountID: number;
+    payerEmail: string;
+    iouReport: OnyxTypes.Report;
+    chatReport: OnyxTypes.Report;
+    transaction: OnyxTypes.Transaction;
+    iouAction: OptimisticIOUReportAction;
+    createdChatReportActionID: string;
+    createdIOUReportActionID: string;
+    reportPreviewAction: OnyxTypes.ReportAction;
+    onyxData: OnyxData;
+};
+
+type SplitData = {
+    chatReportID: string;
+    transactionID: string;
+    reportActionID: string;
+    policyID?: string;
+    createdReportActionID?: string;
+};
+
+type SplitsAndOnyxData = {
+    splitData: SplitData;
+    splits: Split[];
+    onyxData: OnyxData;
+};
+
+type UpdateMoneyRequestData = {
+    params: UpdateMoneyRequestParams;
+    onyxData: OnyxData;
+};
+
+type PayMoneyRequestData = {
+    params: PayMoneyRequestParams;
+    optimisticData: OnyxUpdate[];
+    successData: OnyxUpdate[];
+    failureData: OnyxUpdate[];
+};
+
+type SendMoneyParamsData = {
+    params: SendMoneyParams;
+    optimisticData: OnyxUpdate[];
+    successData: OnyxUpdate[];
+    failureData: OnyxUpdate[];
+};
+
+type OutstandingChildRequest = {
+    hasOutstandingChildRequest?: boolean;
+};
+
+let betas: OnyxTypes.Beta[] = [];
 Onyx.connect({
     key: ONYXKEYS.BETAS,
-    callback: (val) => (betas = val || []),
+    callback: (value) => (betas = value ?? []),
 });
 
-let allPersonalDetails;
+let allPersonalDetails: OnyxTypes.PersonalDetailsList = {};
 Onyx.connect({
     key: ONYXKEYS.PERSONAL_DETAILS_LIST,
-    callback: (val) => {
-        allPersonalDetails = val || {};
+    callback: (value) => {
+        allPersonalDetails = value ?? {};
     },
 });
 
-let allReports;
+let allReports: OnyxCollection<OnyxTypes.Report> = null;
 Onyx.connect({
     key: ONYXKEYS.COLLECTION.REPORT,
     waitForCollectionCallback: true,
-    callback: (val) => (allReports = val),
+    callback: (value) => (allReports = value),
 });
 
-let allTransactions;
+let allTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
 Onyx.connect({
     key: ONYXKEYS.COLLECTION.TRANSACTION,
     waitForCollectionCallback: true,
-    callback: (val) => {
-        if (!val) {
+    callback: (value) => {
+        if (!value) {
             allTransactions = {};
             return;
         }
 
-        allTransactions = val;
+        allTransactions = value;
     },
 });
 
-let allTransactionDrafts = {};
+let allTransactionDrafts: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
 Onyx.connect({
     key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT,
     waitForCollectionCallback: true,
-    callback: (val) => {
-        allTransactionDrafts = val || {};
+    callback: (value) => {
+        allTransactionDrafts = value ?? {};
     },
 });
 
-let allTransactionViolations;
+let allTransactionViolations: NonNullable<OnyxCollection<OnyxTypes.TransactionViolations>> = {};
 Onyx.connect({
     key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
     waitForCollectionCallback: true,
-    callback: (val) => {
-        if (!val) {
+    callback: (value) => {
+        if (!value) {
             allTransactionViolations = {};
             return;
         }
 
-        allTransactionViolations = val;
+        allTransactionViolations = value;
     },
 });
 
-let allDraftSplitTransactions;
+let allDraftSplitTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
 Onyx.connect({
     key: ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT,
     waitForCollectionCallback: true,
-    callback: (val) => {
-        allDraftSplitTransactions = val || {};
+    callback: (value) => {
+        allDraftSplitTransactions = value ?? {};
     },
 });
 
-let allNextSteps = {};
+let allNextSteps: NonNullable<OnyxCollection<OnyxTypes.ReportNextStep>> = {};
 Onyx.connect({
     key: ONYXKEYS.COLLECTION.NEXT_STEP,
     waitForCollectionCallback: true,
-    callback: (val) => {
-        allNextSteps = val || {};
+    callback: (value) => {
+        allNextSteps = value ?? {};
     },
 });
 
-let userAccountID = '';
+let userAccountID = -1;
 let currentUserEmail = '';
 Onyx.connect({
     key: ONYXKEYS.SESSION,
-    callback: (val) => {
-        currentUserEmail = lodashGet(val, 'email', '');
-        userAccountID = lodashGet(val, 'accountID', '');
+    callback: (value) => {
+        currentUserEmail = value?.email ?? '';
+        userAccountID = value?.accountID ?? -1;
     },
 });
 
-let currentUserPersonalDetails = {};
+let currentUserPersonalDetails: OnyxTypes.PersonalDetails | EmptyObject = {};
 Onyx.connect({
     key: ONYXKEYS.PERSONAL_DETAILS_LIST,
-    callback: (val) => {
-        currentUserPersonalDetails = lodashGet(val, userAccountID, {});
+    callback: (value) => {
+        currentUserPersonalDetails = value?.[userAccountID] ?? {};
     },
 });
 
-let currentDate = '';
+let currentDate: OnyxEntry<string> = '';
 Onyx.connect({
     key: ONYXKEYS.CURRENT_DATE,
-    callback: (val) => {
-        currentDate = val;
+    callback: (value) => {
+        currentDate = value;
     },
 });
 
 /**
  * Initialize money request info
- * @param {String} reportID to attach the transaction to
- * @param {Boolean} isFromGlobalCreate
- * @param {String} [iouRequestType] one of manual/scan/distance
+ * @param reportID to attach the transaction to
+ * @param iouRequestType one of manual/scan/distance
  */
-function startMoneyRequest_temporaryForRefactor(reportID, isFromGlobalCreate, iouRequestType = CONST.IOU.REQUEST_TYPE.MANUAL) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function startMoneyRequest_temporaryForRefactor(reportID: string, isFromGlobalCreate: boolean, iouRequestType: IOURequestType = CONST.IOU.REQUEST_TYPE.MANUAL) {
     // Generate a brand new transactionID
     const newTransactionID = CONST.IOU.OPTIMISTIC_TRANSACTION_ID;
+    // Disabling this line since currentDate can be an empty string
+    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
     const created = currentDate || format(new Date(), 'yyyy-MM-dd');
-    const comment = {};
+    const comment: Comment = {};
 
     // Add initial empty waypoints when starting a distance request
     if (iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) {
@@ -158,7 +247,7 @@ function startMoneyRequest_temporaryForRefactor(reportID, isFromGlobalCreate, io
         amount: 0,
         comment,
         created,
-        currency: lodashGet(currentUserPersonalDetails, 'localCurrencyCode', CONST.CURRENCY.USD),
+        currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD,
         iouRequestType,
         reportID,
         transactionID: newTransactionID,
@@ -167,20 +256,12 @@ function startMoneyRequest_temporaryForRefactor(reportID, isFromGlobalCreate, io
     });
 }
 
-/**
- * @param {String} transactionID
- */
-function clearMoneyRequest(transactionID) {
+function clearMoneyRequest(transactionID: string) {
     Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, null);
 }
 
-/**
- * @param {String} transactionID
- * @param {Number} amount
- * @param {String} currency
- * @param {Boolean} [removeOriginalCurrency]
- */
-function setMoneyRequestAmount_temporaryForRefactor(transactionID, amount, currency, removeOriginalCurrency = false) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestAmount_temporaryForRefactor(transactionID: string, amount: number, currency: string, removeOriginalCurrency = false) {
     if (removeOriginalCurrency) {
         Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency, originalCurrency: null});
         return;
@@ -188,20 +269,13 @@ function setMoneyRequestAmount_temporaryForRefactor(transactionID, amount, curre
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {amount, currency});
 }
 
-/**
- * @param {String} transactionID
- * @param {String} created
- */
-function setMoneyRequestCreated_temporaryForRefactor(transactionID, created) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestCreated_temporaryForRefactor(transactionID: string, created: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {created});
 }
 
-/**
- * @param {String} transactionID
- * @param {String} currency
- * @param {Boolean} [removeOriginalCurrency]
- */
-function setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency, removeOriginalCurrency = false) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestCurrency_temporaryForRefactor(transactionID: string, currency: string, removeOriginalCurrency = false) {
     if (removeOriginalCurrency) {
         Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency, originalCurrency: null});
         return;
@@ -209,92 +283,61 @@ function setMoneyRequestCurrency_temporaryForRefactor(transactionID, currency, r
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency});
 }
 
-/**
- * @param {String} transactionID
- * @param {String} originalCurrency
- */
-function setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID, originalCurrency) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestOriginalCurrency_temporaryForRefactor(transactionID: string, originalCurrency: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {originalCurrency});
 }
 
-/**
- * @param {String} transactionID
- * @param {String} comment
- */
-function setMoneyRequestDescription_temporaryForRefactor(transactionID, comment) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestDescription_temporaryForRefactor(transactionID: string, comment: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {comment: {comment: comment.trim()}});
 }
 
-/**
- * @param {String} transactionID
- * @param {String} merchant
- */
-function setMoneyRequestMerchant_temporaryForRefactor(transactionID, merchant) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestMerchant_temporaryForRefactor(transactionID: string, merchant: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {merchant: merchant.trim()});
 }
 
-/**
- * @param {String} transactionID
- * @param {String} category
- */
-function setMoneyRequestCategory_temporaryForRefactor(transactionID, category) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestCategory_temporaryForRefactor(transactionID: string, category: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {category});
 }
 
-/*
- * @param {String} transactionID
- */
-function resetMoneyRequestCategory_temporaryForRefactor(transactionID) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function resetMoneyRequestCategory_temporaryForRefactor(transactionID: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {category: null});
 }
 
-/*
- * @param {String} transactionID
- * @param {String} tag
- */
-function setMoneyRequestTag(transactionID, tag) {
+function setMoneyRequestTag(transactionID: string, tag: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {tag});
 }
 
-/**
- * @param {String} transactionID
- * @param {Boolean} billable
- */
-function setMoneyRequestBillable_temporaryForRefactor(transactionID, billable) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestBillable_temporaryForRefactor(transactionID: string, billable: boolean) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {billable});
 }
 
-/**
- * @param {String} transactionID
- * @param {Object[]} participants
- */
-function setMoneyRequestParticipants_temporaryForRefactor(transactionID, participants) {
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function setMoneyRequestParticipants_temporaryForRefactor(transactionID: string, participants: Participant[]) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants});
 }
 
-/**
- * @param {String} transactionID
- * @param {String} source
- * @param {String} filename
- * @param {Boolean} isDraft
- */
-function setMoneyRequestReceipt(transactionID, source, filename, isDraft) {
+function setMoneyRequestReceipt(transactionID: string, source: string, filename: string, isDraft: boolean) {
     Onyx.merge(`${isDraft ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {
         receipt: {source},
         filename,
     });
 }
 
-/**
- * Reset money request info from the store with its initial value
- * @param {String} id
- */
+/** Reset money request info from the store with its initial value */
 function resetMoneyRequestInfo(id = '') {
+    // Disabling this line since currentDate can be an empty string
+    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
     const created = currentDate || format(new Date(), CONST.DATE.FNS_FORMAT_STRING);
     Onyx.merge(ONYXKEYS.IOU, {
         id,
         amount: 0,
-        currency: lodashGet(currentUserPersonalDetails, 'localCurrencyCode', CONST.CURRENCY.USD),
+        currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD,
         comment: '',
         participants: [],
         merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT,
@@ -309,27 +352,15 @@ function resetMoneyRequestInfo(id = '') {
     });
 }
 
-/**
- *  Helper function to get the receipt error for money requests, or the generic error if there's no receipt
- *
- * @param {Object} receipt
- * @param {String} filename
- * @param {Boolean} [isScanRequest]
- * @returns {Object}
- */
-function getReceiptError(receipt, filename, isScanRequest = true) {
-    return _.isEmpty(receipt) || !isScanRequest
+/** Helper function to get the receipt error for money requests, or the generic error if there's no receipt */
+function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true): Errors | ErrorFields {
+    return isEmptyObject(receipt) || !isScanRequest
         ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage')
-        : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source, filename});
+        : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source?.toString() ?? '', filename: filename ?? ''});
 }
 
-/**
- * Return the object to update hasOutstandingChildRequest
- * @param {Object} [policy]
- * @param {Boolean} needsToBeManuallySubmitted
- * @returns {Object}
- */
-function getOutstandingChildRequest(policy, needsToBeManuallySubmitted) {
+/** Return the object to update hasOutstandingChildRequest */
+function getOutstandingChildRequest(needsToBeManuallySubmitted: boolean, policy: OnyxEntry<OnyxTypes.Policy> | EmptyObject = null): OutstandingChildRequest {
     if (!needsToBeManuallySubmitted) {
         return {
             hasOutstandingChildRequest: false,
@@ -346,49 +377,31 @@ function getOutstandingChildRequest(policy, needsToBeManuallySubmitted) {
     return {};
 }
 
-/**
- * Builds the Onyx data for a money request.
- *
- * @param {Object} chatReport
- * @param {Object} iouReport
- * @param {Object} transaction
- * @param {Object} chatCreatedAction
- * @param {Object} iouCreatedAction
- * @param {Object} iouAction
- * @param {Object} optimisticPersonalDetailListAction
- * @param {Object} reportPreviewAction
- * @param {Array} optimisticPolicyRecentlyUsedCategories
- * @param {Array} optimisticPolicyRecentlyUsedTags
- * @param {boolean} isNewChatReport
- * @param {boolean} shouldCreateNewMoneyRequestReport
- * @param {Object} policy - May be undefined, an empty object, or an object matching the Policy type (src/types/onyx/Policy.ts)
- * @param {Array} policyTags
- * @param {Array} policyCategories
- * @param {Boolean} needsToBeManuallySubmitted
- * @returns {Array} - An array containing the optimistic data, success data, and failure data.
- */
+/** Builds the Onyx data for a money request */
 function buildOnyxDataForMoneyRequest(
-    chatReport,
-    iouReport,
-    transaction,
-    chatCreatedAction,
-    iouCreatedAction,
-    iouAction,
-    optimisticPersonalDetailListAction,
-    reportPreviewAction,
-    optimisticPolicyRecentlyUsedCategories,
-    optimisticPolicyRecentlyUsedTags,
-    isNewChatReport,
-    shouldCreateNewMoneyRequestReport,
-    policy,
-    policyTags,
-    policyCategories,
+    chatReport: OnyxEntry<OnyxTypes.Report>,
+    iouReport: OnyxTypes.Report,
+    transaction: OnyxTypes.Transaction,
+    chatCreatedAction: OptimisticCreatedReportAction,
+    iouCreatedAction: OptimisticCreatedReportAction,
+    iouAction: OptimisticIOUReportAction,
+    optimisticPersonalDetailListAction: OnyxTypes.PersonalDetailsList,
+    reportPreviewAction: ReportAction,
+    optimisticPolicyRecentlyUsedCategories: string[],
+    optimisticPolicyRecentlyUsedTags: OnyxTypes.RecentlyUsedTags,
+    isNewChatReport: boolean,
+    shouldCreateNewMoneyRequestReport: boolean,
+    policy?: OnyxTypes.Policy | EmptyObject,
+    policyTags?: OnyxTypes.PolicyTags,
+    policyCategories?: OnyxTypes.PolicyCategories,
     needsToBeManuallySubmitted = true,
-) {
+): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] {
     const isScanRequest = TransactionUtils.isScanRequest(transaction);
     const outstandingChildRequest = getOutstandingChildRequest(needsToBeManuallySubmitted, policy);
-    const optimisticData = [
-        {
+    const optimisticData: OnyxUpdate[] = [];
+
+    if (chatReport) {
+        optimisticData.push({
             // Use SET for new reports because it doesn't exist yet, is faster and we need the data to be available when we navigate to the chat page
             onyxMethod: isNewChatReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
@@ -400,14 +413,17 @@ function buildOnyxDataForMoneyRequest(
                 ...outstandingChildRequest,
                 ...(isNewChatReport ? {pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}} : {}),
             },
-        },
+        });
+    }
+
+    optimisticData.push(
         {
             onyxMethod: shouldCreateNewMoneyRequestReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
             value: {
                 ...iouReport,
-                lastMessageText: iouAction.message[0].text,
-                lastMessageHtml: iouAction.message[0].html,
+                lastMessageText: iouAction.message?.[0].text,
+                lastMessageHtml: iouAction.message?.[0].html,
                 pendingFields: {
                     ...(shouldCreateNewMoneyRequestReport ? {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : {preview: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}),
                 },
@@ -418,22 +434,38 @@ function buildOnyxDataForMoneyRequest(
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`,
             value: transaction,
         },
-        {
-            onyxMethod: isNewChatReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`,
-            value: {
-                ...(isNewChatReport ? {[chatCreatedAction.reportActionID]: chatCreatedAction} : {}),
-                [reportPreviewAction.reportActionID]: reportPreviewAction,
-            },
-        },
-        {
-            onyxMethod: shouldCreateNewMoneyRequestReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
-            value: {
-                ...(shouldCreateNewMoneyRequestReport ? {[iouCreatedAction.reportActionID]: iouCreatedAction} : {}),
-                [iouAction.reportActionID]: iouAction,
-            },
-        },
+        isNewChatReport
+            ? {
+                  onyxMethod: Onyx.METHOD.SET,
+                  key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
+                  value: {
+                      [chatCreatedAction.reportActionID]: chatCreatedAction,
+                      [reportPreviewAction.reportActionID]: reportPreviewAction,
+                  },
+              }
+            : {
+                  onyxMethod: Onyx.METHOD.MERGE,
+                  key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
+                  value: {
+                      [reportPreviewAction.reportActionID]: reportPreviewAction,
+                  },
+              },
+        shouldCreateNewMoneyRequestReport
+            ? {
+                  onyxMethod: Onyx.METHOD.SET,
+                  key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
+                  value: {
+                      [iouCreatedAction.reportActionID]: iouCreatedAction as OnyxTypes.ReportAction,
+                      [iouAction.reportActionID]: iouAction as OnyxTypes.ReportAction,
+                  },
+              }
+            : {
+                  onyxMethod: Onyx.METHOD.MERGE,
+                  key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
+                  value: {
+                      [iouAction.reportActionID]: iouAction as OnyxTypes.ReportAction,
+                  },
+              },
 
         // Remove the temporary transaction used during the creation flow
         {
@@ -441,9 +473,9 @@ function buildOnyxDataForMoneyRequest(
             key: `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`,
             value: null,
         },
-    ];
+    );
 
-    if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) {
+    if (optimisticPolicyRecentlyUsedCategories.length) {
         optimisticData.push({
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`,
@@ -451,7 +483,7 @@ function buildOnyxDataForMoneyRequest(
         });
     }
 
-    if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) {
+    if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) {
         optimisticData.push({
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`,
@@ -459,7 +491,7 @@ function buildOnyxDataForMoneyRequest(
         });
     }
 
-    if (!_.isEmpty(optimisticPersonalDetailListAction)) {
+    if (!isEmptyObject(optimisticPersonalDetailListAction)) {
         optimisticData.push({
             onyxMethod: Onyx.METHOD.MERGE,
             key: ONYXKEYS.PERSONAL_DETAILS_LIST,
@@ -467,19 +499,20 @@ function buildOnyxDataForMoneyRequest(
         });
     }
 
-    const successData = [
-        ...(isNewChatReport
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
-                      value: {
-                          pendingFields: null,
-                          errorFields: null,
-                      },
-                  },
-              ]
-            : []),
+    const successData: OnyxUpdate[] = [];
+
+    if (isNewChatReport) {
+        successData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
+            value: {
+                pendingFields: null,
+                errorFields: null,
+            },
+        });
+    }
+
+    successData.push(
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
@@ -499,7 +532,7 @@ function buildOnyxDataForMoneyRequest(
 
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
             value: {
                 ...(isNewChatReport
                     ? {
@@ -532,17 +565,17 @@ function buildOnyxDataForMoneyRequest(
                 },
             },
         },
-    ];
+    );
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
             value: {
-                iouReportID: chatReport.iouReportID,
-                lastReadTime: chatReport.lastReadTime,
+                iouReportID: chatReport?.iouReportID,
+                lastReadTime: chatReport?.lastReadTime,
                 pendingFields: null,
-                hasOutstandingChildRequest: chatReport.hasOutstandingChildRequest,
+                hasOutstandingChildRequest: chatReport?.hasOutstandingChildRequest,
                 ...(isNewChatReport
                     ? {
                           errorFields: {
@@ -581,12 +614,14 @@ function buildOnyxDataForMoneyRequest(
 
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
             value: {
                 ...(isNewChatReport
                     ? {
                           [chatCreatedAction.reportActionID]: {
-                              errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt.filename, isScanRequest),
+                              // Disabling this line since transaction.filename can be an empty string
+                              // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+                              errors: getReceiptError(transaction?.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest),
                           },
                           [reportPreviewAction.reportActionID]: {
                               errors: ErrorUtils.getMicroSecondOnyxError(null),
@@ -595,7 +630,9 @@ function buildOnyxDataForMoneyRequest(
                     : {
                           [reportPreviewAction.reportActionID]: {
                               created: reportPreviewAction.created,
-                              errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt.filename, isScanRequest),
+                              // Disabling this line since transaction.filename can be an empty string
+                              // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+                              errors: getReceiptError(transaction?.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest),
                           },
                       }),
             },
@@ -607,7 +644,9 @@ function buildOnyxDataForMoneyRequest(
                 ...(shouldCreateNewMoneyRequestReport
                     ? {
                           [iouCreatedAction.reportActionID]: {
-                              errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt.filename, isScanRequest),
+                              // Disabling this line since transaction.filename can be an empty string
+                              // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+                              errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest),
                           },
                           [iouAction.reportActionID]: {
                               errors: ErrorUtils.getMicroSecondOnyxError(null),
@@ -615,7 +654,9 @@ function buildOnyxDataForMoneyRequest(
                       }
                     : {
                           [iouAction.reportActionID]: {
-                              errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt.filename, isScanRequest),
+                              // Disabling this line since transaction.filename can be an empty string
+                              // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+                              errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest),
                           },
                       }),
             },
@@ -623,11 +664,11 @@ function buildOnyxDataForMoneyRequest(
     ];
 
     // Policy won't be set for P2P cases for which we don't need to compute violations
-    if (!policy || !policy.id) {
+    if (!policy?.id) {
         return [optimisticData, successData, failureData];
     }
 
-    const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], policy.requiresTag, policyTags, policy.requiresCategory, policyCategories);
+    const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], !!policy.requiresTag, policyTags ?? {}, !!policy.requiresCategory, policyCategories ?? {});
 
     if (violationsOnyxData) {
         optimisticData.push(violationsOnyxData);
@@ -644,71 +685,39 @@ function buildOnyxDataForMoneyRequest(
 /**
  * Gathers all the data needed to make a money request. It attempts to find existing reports, iouReports, and receipts. If it doesn't find them, then
  * it creates optimistic versions of them and uses those instead
- *
- * @param {Object} parentChatReport
- * @param {Object} participant
- * @param {String} comment
- * @param {Number} amount
- * @param {String} currency
- * @param {String} created
- * @param {String} merchant
- * @param {Number} [payeeAccountID]
- * @param {String} [payeeEmail]
- * @param {Object} [receipt]
- * @param {String} [existingTransactionID]
- * @param {String} [category]
- * @param {String} [tag]
- * @param {Boolean} [billable]
- * @param {Object} [policy]
- * @param {Object} [policyTags]
- * @param {Object} [policyCategories]
- * @param {Number} [moneyRequestReportID] - If user requests money via the report composer on some money request report, we always add a request to that specific report.
- * @returns {Object} data
- * @returns {String} data.payerEmail
- * @returns {Object} data.iouReport
- * @returns {Object} data.chatReport
- * @returns {Object} data.transaction
- * @returns {Object} data.iouAction
- * @returns {Object} data.createdChatReportActionID
- * @returns {Object} data.createdIOUReportActionID
- * @returns {Object} data.reportPreviewAction
- * @returns {Object} data.onyxData
- * @returns {Object} data.onyxData.optimisticData
- * @returns {Object} data.onyxData.successData
- * @returns {Object} data.onyxData.failureData
  */
 function getMoneyRequestInformation(
-    parentChatReport,
-    participant,
-    comment,
-    amount,
-    currency,
-    created,
-    merchant,
+    parentChatReport: OnyxEntry<OnyxTypes.Report> | EmptyObject,
+    participant: Participant,
+    comment: string,
+    amount: number,
+    currency: string,
+    created: string,
+    merchant: string,
+    receipt: Receipt | undefined,
+    existingTransactionID: string | undefined,
+    category: string | undefined,
+    tag: string | undefined,
+    billable: boolean | undefined,
+    policy: OnyxTypes.Policy | EmptyObject | undefined,
+    policyTags: OnyxTypes.PolicyTags | undefined,
+    policyCategories: OnyxTypes.PolicyCategories | undefined,
     payeeAccountID = userAccountID,
     payeeEmail = currentUserEmail,
-    receipt = undefined,
-    existingTransactionID = undefined,
-    category = undefined,
-    tag = undefined,
-    billable = undefined,
-    policy = undefined,
-    policyTags = undefined,
-    policyCategories = undefined,
-    moneyRequestReportID = 0,
-) {
-    const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login);
+    moneyRequestReportID = '',
+): MoneyRequestInformation {
+    const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? '');
     const payerAccountID = Number(participant.accountID);
     const isPolicyExpenseChat = participant.isPolicyExpenseChat;
 
     // STEP 1: Get existing chat report OR build a new optimistic one
     let isNewChatReport = false;
-    let chatReport = lodashGet(parentChatReport, 'reportID', null) ? parentChatReport : null;
+    let chatReport = !isEmptyObject(parentChatReport) && parentChatReport?.reportID ? parentChatReport : null;
 
     // If this is a policyExpenseChat, the chatReport must exist and we can get it from Onyx.
     // report is null if the flow is initiated from the global create menu. However, participant always stores the reportID if it exists, which is the case for policyExpenseChats
     if (!chatReport && isPolicyExpenseChat) {
-        chatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`];
+        chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`] ?? null;
     }
 
     if (!chatReport) {
@@ -723,22 +732,22 @@ function getMoneyRequestInformation(
 
     // STEP 2: Get the money request report. If the moneyRequestReportID has been provided, we want to add the transaction to this specific report.
     // If no such reportID has been provided, let's use the chatReport.iouReportID property. In case that is not present, build a new optimistic money request report.
-    let iouReport = null;
+    let iouReport: OnyxEntry<OnyxTypes.Report> = null;
     const shouldCreateNewMoneyRequestReport = !moneyRequestReportID && (!chatReport.iouReportID || ReportUtils.hasIOUWaitingOnCurrentUserBankAccount(chatReport));
-    if (moneyRequestReportID > 0) {
-        iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReportID}`];
+    if (moneyRequestReportID) {
+        iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReportID}`] ?? null;
     } else if (!shouldCreateNewMoneyRequestReport) {
-        iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`];
+        iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`] ?? null;
     }
 
     // Check if the Scheduled Submit is enabled in case of expense report
     let needsToBeManuallySubmitted = true;
     let isFromPaidPolicy = false;
     if (isPolicyExpenseChat) {
-        isFromPaidPolicy = PolicyUtils.isPaidGroupPolicy(policy);
+        isFromPaidPolicy = PolicyUtils.isPaidGroupPolicy(policy ?? null);
 
         // If the scheduled submit is turned off on the policy, user needs to manually submit the report which is indicated by GBR in LHN
-        needsToBeManuallySubmitted = isFromPaidPolicy && !(lodashGet(policy, 'harvesting.enabled', policy.isHarvestingEnabled) || false);
+        needsToBeManuallySubmitted = isFromPaidPolicy && !(policy?.harvesting?.enabled ?? policy?.isHarvestingEnabled);
 
         // If the linked expense report on paid policy is not draft, we need to create a new draft expense report
         if (iouReport && isFromPaidPolicy && !ReportUtils.isDraftExpenseReport(iouReport)) {
@@ -749,7 +758,7 @@ function getMoneyRequestInformation(
     if (iouReport) {
         if (isPolicyExpenseChat) {
             iouReport = {...iouReport};
-            if (lodashGet(iouReport, 'currency') === currency) {
+            if (iouReport?.currency === currency && typeof iouReport.total === 'number') {
                 // Because of the Expense reports are stored as negative values, we substract the total from the amount
                 iouReport.total -= amount;
             }
@@ -758,16 +767,16 @@ function getMoneyRequestInformation(
         }
     } else {
         iouReport = isPolicyExpenseChat
-            ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID, payeeAccountID, amount, currency)
+            ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID ?? '', payeeAccountID, amount, currency)
             : ReportUtils.buildOptimisticIOUReport(payeeAccountID, payerAccountID, amount, chatReport.reportID, currency);
     }
 
     // STEP 3: Build optimistic receipt and transaction
-    const receiptObject = {};
+    const receiptObject: Receipt = {};
     let filename;
-    if (receipt && receipt.source) {
+    if (receipt?.source) {
         receiptObject.source = receipt.source;
-        receiptObject.state = receipt.state || CONST.IOU.RECEIPT_STATE.SCANREADY;
+        receiptObject.state = receipt.state ?? CONST.IOU.RECEIPT_STATE.SCANREADY;
         filename = receipt.name;
     }
     let optimisticTransaction = TransactionUtils.buildOptimisticTransaction(
@@ -798,7 +807,7 @@ function getMoneyRequestInformation(
     // to remind me to do this.
     const existingTransaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`];
     if (existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) {
-        optimisticTransaction = fastMerge(existingTransaction, optimisticTransaction);
+        optimisticTransaction = fastMerge(existingTransaction, optimisticTransaction, false);
     }
 
     // STEP 4: Build optimistic reportActions. We need:
@@ -817,7 +826,7 @@ function getMoneyRequestInformation(
         comment,
         [participant],
         optimisticTransaction.transactionID,
-        '',
+        undefined,
         iouReport.reportID,
         false,
         false,
@@ -844,12 +853,14 @@ function getMoneyRequestInformation(
               [payerAccountID]: {
                   accountID: payerAccountID,
                   avatar: UserUtils.getDefaultAvatarURL(payerAccountID),
+                  // Disabling this line since participant.displayName can be an empty string
+                  // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
                   displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || payerEmail),
                   login: participant.login,
                   isOptimisticPersonalDetail: true,
               },
           }
-        : undefined;
+        : {};
 
     // STEP 5: Build Onyx Data
     const [optimisticData, successData, failureData] = buildOnyxDataForMoneyRequest(
@@ -878,8 +889,8 @@ function getMoneyRequestInformation(
         chatReport,
         transaction: optimisticTransaction,
         iouAction,
-        createdChatReportActionID: isNewChatReport ? optimisticCreatedActionForChat.reportActionID : 0,
-        createdIOUReportActionID: shouldCreateNewMoneyRequestReport ? optimisticCreatedActionForIOU.reportActionID : 0,
+        createdChatReportActionID: isNewChatReport ? optimisticCreatedActionForChat.reportActionID : '0',
+        createdIOUReportActionID: shouldCreateNewMoneyRequestReport ? optimisticCreatedActionForIOU.reportActionID : '0',
         reportPreviewAction,
         onyxData: {
             optimisticData,
@@ -889,33 +900,31 @@ function getMoneyRequestInformation(
     };
 }
 
-/**
- * Requests money based on a distance (eg. mileage from a map)
- *
- * @param {Object} report
- * @param {Object} participant
- * @param {String} comment
- * @param {String} created
- * @param {String} [category]
- * @param {String} [tag]
- * @param {Number} amount
- * @param {String} currency
- * @param {String} merchant
- * @param {Boolean} [billable]
- * @param {Object} validWaypoints
- * @param {Object} policy - May be undefined, an empty object, or an object matching the Policy type (src/types/onyx/Policy.ts)
- * @param {Array} policyTags
- * @param {Array} policyCategories
- */
-function createDistanceRequest(report, participant, comment, created, category, tag, amount, currency, merchant, billable, validWaypoints, policy, policyTags, policyCategories) {
+/** Requests money based on a distance (eg. mileage from a map) */
+function createDistanceRequest(
+    report: OnyxTypes.Report,
+    participant: Participant,
+    comment: string,
+    created: string,
+    category: string | undefined,
+    tag: string | undefined,
+    amount: number,
+    currency: string,
+    merchant: string,
+    billable: boolean | undefined,
+    validWaypoints: WaypointCollection,
+    policy: OnyxTypes.Policy | EmptyObject | undefined,
+    policyTags: OnyxTypes.PolicyTags,
+    policyCategories: OnyxTypes.PolicyCategories,
+) {
     // If the report is an iou or expense report, we should get the linked chat report to be passed to the getMoneyRequestInformation function
     const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report);
     const currentChatReport = isMoneyRequestReport ? ReportUtils.getReport(report.chatReportID) : report;
-    const moneyRequestReportID = isMoneyRequestReport ? report.reportID : 0;
+    const moneyRequestReportID = isMoneyRequestReport ? report.reportID : '';
     const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created);
 
-    const optimisticReceipt = {
-        source: ReceiptGeneric,
+    const optimisticReceipt: Receipt = {
+        source: ReceiptGeneric as ReceiptSource,
         state: CONST.IOU.RECEIPT_STATE.OPEN,
     };
     const {iouReport, chatReport, transaction, iouAction, createdChatReportActionID, createdIOUReportActionID, reportPreviewAction, onyxData} = getMoneyRequestInformation(
@@ -926,8 +935,6 @@ function createDistanceRequest(report, participant, comment, created, category,
         currency,
         currentCreated,
         merchant,
-        userAccountID,
-        currentUserEmail,
         optimisticReceipt,
         undefined,
         category,
@@ -936,71 +943,76 @@ function createDistanceRequest(report, participant, comment, created, category,
         policy,
         policyTags,
         policyCategories,
+        userAccountID,
+        currentUserEmail,
         moneyRequestReportID,
     );
-    API.write(
-        'CreateDistanceRequest',
-        {
-            comment,
-            iouReportID: iouReport.reportID,
-            chatReportID: chatReport.reportID,
-            transactionID: transaction.transactionID,
-            reportActionID: iouAction.reportActionID,
-            createdChatReportActionID,
-            createdIOUReportActionID,
-            reportPreviewReportActionID: reportPreviewAction.reportActionID,
-            waypoints: JSON.stringify(validWaypoints),
-            created: currentCreated,
-            category,
-            tag,
-            billable,
-        },
-        onyxData,
-    );
+
+    const parameters: CreateDistanceRequestParams = {
+        comment,
+        iouReportID: iouReport.reportID,
+        chatReportID: chatReport.reportID,
+        transactionID: transaction.transactionID,
+        reportActionID: iouAction.reportActionID,
+        createdChatReportActionID,
+        createdIOUReportActionID,
+        reportPreviewReportActionID: reportPreviewAction.reportActionID,
+        waypoints: JSON.stringify(validWaypoints),
+        created: currentCreated,
+        category,
+        tag,
+        billable,
+    };
+
+    API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData);
     Navigation.dismissModal(isMoneyRequestReport ? report.reportID : chatReport.reportID);
     Report.notifyNewAction(chatReport.reportID, userAccountID);
 }
 
 /**
- * @param {String} transactionID
- * @param {String} transactionThreadReportID
- * @param {Object} transactionChanges
- * @param {String} [transactionChanges.created] Present when updated the date field
- * @param {Boolean} onlyIncludeChangedFields
- *                      When 'true', then the returned params will only include the transaction details for the fields that were changed.
- *                      When `false`, then the returned params will include all the transaction details, regardless of which fields were changed.
- *                      This setting is necessary while the UpdateDistanceRequest API is refactored to be fully 1:1:1 in https://github.com/Expensify/App/issues/28358
- * @returns {object}
- */
-function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, onlyIncludeChangedFields) {
-    const optimisticData = [];
-    const successData = [];
-    const failureData = [];
+ * @param transactionChanges
+ * @param [transactionChanges.created] Present when updated the date field
+ * @param onlyIncludeChangedFields
+ *               When 'true', then the returned params will only include the transaction details for the fields that were changed.
+ *               When `false`, then the returned params will include all the transaction details, regardless of which fields were changed.
+ *               This setting is necessary while the UpdateDistanceRequest API is refactored to be fully 1:1:1 in https://github.com/Expensify/App/issues/28358
+ */
+function getUpdateMoneyRequestParams(
+    transactionID: string,
+    transactionThreadReportID: string,
+    transactionChanges: TransactionChanges,
+    onlyIncludeChangedFields: boolean,
+): UpdateMoneyRequestData {
+    const optimisticData: OnyxUpdate[] = [];
+    const successData: OnyxUpdate[] = [];
+    const failureData: OnyxUpdate[] = [];
 
     // Step 1: Set any "pending fields" (ones updated while the user was offline) to have error messages in the failureData
-    const pendingFields = _.mapObject(transactionChanges, () => CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE);
-    const clearedPendingFields = _.mapObject(transactionChanges, () => null);
-    const errorFields = _.mapObject(pendingFields, () => ({
-        [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericEditFailureMessage'),
-    }));
+    const pendingFields = Object.fromEntries(Object.keys(transactionChanges).map((key) => [key, CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE]));
+    const clearedPendingFields = Object.fromEntries(Object.keys(transactionChanges).map((key) => [key, null]));
+    const errorFields = Object.fromEntries(Object.keys(pendingFields).map((key) => [key, {[DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericEditFailureMessage')}]));
 
     // Step 2: Get all the collections being updated
-    const transactionThread = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`];
-    const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
-    const iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread.parentReportID}`];
+    const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null;
+    const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
+    const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread?.parentReportID}`] ?? null;
     const isFromExpenseReport = ReportUtils.isExpenseReport(iouReport);
     const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);
-    const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport);
+    const updatedTransaction = transaction ? TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport) : null;
     const transactionDetails = ReportUtils.getTransactionDetails(updatedTransaction);
 
-    // This needs to be a JSON string since we're sending this to the MapBox API
-    transactionDetails.waypoints = JSON.stringify(transactionDetails.waypoints);
+    if (transactionDetails?.waypoints) {
+        // This needs to be a JSON string since we're sending this to the MapBox API
+        transactionDetails.waypoints = JSON.stringify(transactionDetails.waypoints);
+    }
 
-    const dataToIncludeInParams = onlyIncludeChangedFields ? _.pick(transactionDetails, _.keys(transactionChanges)) : transactionDetails;
+    const dataToIncludeInParams: Partial<TransactionDetails> | undefined = onlyIncludeChangedFields
+        ? Object.fromEntries(Object.entries(transactionDetails ?? {}).filter(([key]) => Object.keys(transactionChanges).includes(key)))
+        : transactionDetails;
 
-    const params = {
+    const params: UpdateMoneyRequestParams = {
         ...dataToIncludeInParams,
-        reportID: iouReport.reportID,
+        reportID: iouReport?.reportID,
         transactionID,
     };
 
@@ -1008,30 +1020,30 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t
     // We don't create a modified report action if we're updating the waypoints,
     // since there isn't actually any optimistic data we can create for them and the report action is created on the server
     // with the response from the MapBox API
-    if (!_.has(transactionChanges, 'waypoints')) {
+    if (!('waypoints' in transactionChanges)) {
         const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport);
         params.reportActionID = updatedReportAction.reportActionID;
 
         optimisticData.push({
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`,
             value: {
-                [updatedReportAction.reportActionID]: updatedReportAction,
+                [updatedReportAction.reportActionID]: updatedReportAction as OnyxTypes.ReportAction,
             },
         });
         successData.push({
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`,
             value: {
                 [updatedReportAction.reportActionID]: {pendingAction: null},
             },
         });
         failureData.push({
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`,
             value: {
                 [updatedReportAction.reportActionID]: {
-                    ...updatedReportAction,
+                    ...(updatedReportAction as OnyxTypes.ReportAction),
                     errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericEditFailureMessage'),
                 },
             },
@@ -1041,23 +1053,25 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t
         // Should only update if the transaction matches the currency of the report, else we wait for the update
         // from the server with the currency conversion
         let updatedMoneyRequestReport = {...iouReport};
-        if (updatedTransaction.currency === iouReport.currency && updatedTransaction.modifiedAmount) {
+        if (updatedTransaction?.currency === iouReport?.currency && updatedTransaction?.modifiedAmount) {
             const diff = TransactionUtils.getAmount(transaction, true) - TransactionUtils.getAmount(updatedTransaction, true);
-            if (ReportUtils.isExpenseReport(iouReport)) {
+            if (ReportUtils.isExpenseReport(iouReport) && typeof updatedMoneyRequestReport.total === 'number') {
                 updatedMoneyRequestReport.total += diff;
             } else {
-                updatedMoneyRequestReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID, diff, TransactionUtils.getCurrency(transaction), false);
+                updatedMoneyRequestReport = iouReport
+                    ? IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, TransactionUtils.getCurrency(transaction), false)
+                    : {};
             }
 
             updatedMoneyRequestReport.cachedTotal = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedTransaction.currency);
             optimisticData.push({
                 onyxMethod: Onyx.METHOD.MERGE,
-                key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
+                key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
                 value: updatedMoneyRequestReport,
             });
             successData.push({
                 onyxMethod: Onyx.METHOD.MERGE,
-                key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
+                key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
                 value: {pendingAction: null},
             });
         }
@@ -1070,54 +1084,53 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t
         value: {
             ...updatedTransaction,
             pendingFields,
-            isLoading: _.has(transactionChanges, 'waypoints'),
+            isLoading: 'waypoints' in transactionChanges,
             errorFields: null,
         },
     });
 
-    if (isScanning && (_.has(transactionChanges, 'amount') || _.has(transactionChanges, 'currency'))) {
+    if (isScanning && ('amount' in transactionChanges || 'currency' in transactionChanges)) {
         optimisticData.push(
-            ...[
-                {
-                    onyxMethod: Onyx.METHOD.MERGE,
-                    key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
-                    value: {
-                        [transactionThread.parentReportActionID]: {
-                            whisperedToAccountIDs: [],
-                        },
+            {
+                onyxMethod: Onyx.METHOD.MERGE,
+                key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
+                value: {
+                    [transactionThread?.parentReportActionID ?? '']: {
+                        whisperedToAccountIDs: [],
                     },
                 },
-                {
-                    onyxMethod: Onyx.METHOD.MERGE,
-                    key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`,
-                    value: {
-                        [iouReport.parentReportActionID]: {
-                            whisperedToAccountIDs: [],
-                        },
+            },
+            {
+                onyxMethod: Onyx.METHOD.MERGE,
+                key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.parentReportID}`,
+                value: {
+                    [iouReport?.parentReportActionID ?? '']: {
+                        whisperedToAccountIDs: [],
                     },
                 },
-            ],
+            },
         );
     }
+
     // Update recently used categories if the category is changed
-    if (_.has(transactionChanges, 'category')) {
-        const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, transactionChanges.category);
-        if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) {
+    if ('category' in transactionChanges) {
+        const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport?.policyID, transactionChanges.category);
+        if (optimisticPolicyRecentlyUsedCategories.length) {
             optimisticData.push({
                 onyxMethod: Onyx.METHOD.SET,
-                key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`,
+                key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport?.policyID}`,
                 value: optimisticPolicyRecentlyUsedCategories,
             });
         }
     }
 
     // Update recently used categories if the tag is changed
-    if (_.has(transactionChanges, 'tag')) {
-        const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, transactionChanges.tag);
-        if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) {
+    if ('tag' in transactionChanges) {
+        const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag);
+        if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) {
             optimisticData.push({
                 onyxMethod: Onyx.METHOD.MERGE,
-                key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`,
+                key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport?.policyID}`,
                 value: optimisticPolicyRecentlyUsedTags,
             });
         }
@@ -1134,7 +1147,7 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t
         },
     });
 
-    if (_.has(transactionChanges, 'waypoints')) {
+    if ('waypoints' in transactionChanges) {
         // Delete the draft transaction when editing waypoints when the server responds successfully and there are no errors
         successData.push({
             onyxMethod: Onyx.METHOD.SET,
@@ -1154,12 +1167,14 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t
         },
     });
 
-    // Reset the iouReport to it's original state
-    failureData.push({
-        onyxMethod: Onyx.METHOD.MERGE,
-        key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
-        value: iouReport,
-    });
+    if (iouReport) {
+        // Reset the iouReport to it's original state
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
+            value: iouReport,
+        });
+    }
 
     return {
         params,
@@ -1167,166 +1182,95 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t
     };
 }
 
-/**
- * Updates the created date of a money request
- *
- * @param {String} transactionID
- * @param {String} transactionThreadReportID
- * @param {String} val
- */
-function updateMoneyRequestDate(transactionID, transactionThreadReportID, val) {
-    const transactionChanges = {
-        created: val,
+/** Updates the created date of a money request */
+function updateMoneyRequestDate(transactionID: string, transactionThreadReportID: string, value: string) {
+    const transactionChanges: TransactionChanges = {
+        created: value,
     };
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true);
-    API.write('UpdateMoneyRequestDate', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DATE, params, onyxData);
 }
 
-/**
- * Updates the billable field of a money request
- *
- * @param {String} transactionID
- * @param {String} transactionThreadReportID
- * @param {Boolean} val
- */
-function updateMoneyRequestBillable(transactionID, transactionThreadReportID, val) {
-    const transactionChanges = {
-        billable: val,
+/** Updates the billable field of a money request */
+function updateMoneyRequestBillable(transactionID: string, transactionThreadReportID: string, value: boolean) {
+    const transactionChanges: TransactionChanges = {
+        billable: value,
     };
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true);
-    API.write('UpdateMoneyRequestBillable', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_BILLABLE, params, onyxData);
 }
 
-/**
- * Updates the merchant field of a money request
- *
- * @param {String} transactionID
- * @param {Number} transactionThreadReportID
- * @param {String} val
- */
-function updateMoneyRequestMerchant(transactionID, transactionThreadReportID, val) {
-    const transactionChanges = {
-        merchant: val,
+/** Updates the merchant field of a money request */
+function updateMoneyRequestMerchant(transactionID: string, transactionThreadReportID: string, value: string) {
+    const transactionChanges: TransactionChanges = {
+        merchant: value,
     };
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true);
-    API.write('UpdateMoneyRequestMerchant', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_MERCHANT, params, onyxData);
 }
 
-/**
- * Updates the tag of a money request
- *
- * @param {String} transactionID
- * @param {Number} transactionThreadReportID
- * @param {String} tag
- */
-function updateMoneyRequestTag(transactionID, transactionThreadReportID, tag) {
-    const transactionChanges = {
+/** Updates the tag of a money request */
+function updateMoneyRequestTag(transactionID: string, transactionThreadReportID: string, tag: string) {
+    const transactionChanges: TransactionChanges = {
         tag,
     };
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true);
-    API.write('UpdateMoneyRequestTag', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_TAG, params, onyxData);
 }
 
-/**
- * Updates the waypoints of a distance money request
- *
- * @param {String} transactionID
- * @param {Number} transactionThreadReportID
- * @param {Object} waypoints
- */
-function updateMoneyRequestDistance(transactionID, transactionThreadReportID, waypoints) {
-    const transactionChanges = {
+/** Updates the waypoints of a distance money request */
+function updateMoneyRequestDistance(transactionID: string, transactionThreadReportID: string, waypoints: WaypointCollection) {
+    const transactionChanges: TransactionChanges = {
         waypoints,
     };
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true);
-    API.write('UpdateMoneyRequestDistance', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DISTANCE, params, onyxData);
 }
 
-/**
- * Updates the category of a money request
- *
- * @param {String} transactionID
- * @param {Number} transactionThreadReportID
- * @param {String} category
- */
-function updateMoneyRequestCategory(transactionID, transactionThreadReportID, category) {
-    const transactionChanges = {
+/** Updates the category of a money request */
+function updateMoneyRequestCategory(transactionID: string, transactionThreadReportID: string, category: string) {
+    const transactionChanges: TransactionChanges = {
         category,
     };
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true);
-    API.write('UpdateMoneyRequestCategory', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_CATEGORY, params, onyxData);
 }
 
-/**
- * Updates the description of a money request
- *
- * @param {String} transactionID
- * @param {Number} transactionThreadReportID
- * @param {String} comment
- */
-function updateMoneyRequestDescription(transactionID, transactionThreadReportID, comment) {
-    const transactionChanges = {
+/** Updates the description of a money request */
+function updateMoneyRequestDescription(transactionID: string, transactionThreadReportID: string, comment: string) {
+    const transactionChanges: TransactionChanges = {
         comment,
     };
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true);
-    API.write('UpdateMoneyRequestDescription', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_DESCRIPTION, params, onyxData);
 }
 
-/**
- * Edits an existing distance request
- *
- * @param {String} transactionID
- * @param {String} transactionThreadReportID
- * @param {Object} transactionChanges
- * @param {String} [transactionChanges.created]
- * @param {Number} [transactionChanges.amount]
- * @param {Object} [transactionChanges.comment]
- * @param {Object} [transactionChanges.waypoints]
- *
- */
-function updateDistanceRequest(transactionID, transactionThreadReportID, transactionChanges) {
+/** Edits an existing distance request */
+function updateDistanceRequest(transactionID: string, transactionThreadReportID: string, transactionChanges: TransactionChanges) {
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, false);
-    API.write('UpdateDistanceRequest', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_DISTANCE_REQUEST, params, onyxData);
 }
 
 /**
  * Request money from another user
- *
- * @param {Object} report
- * @param {Number} amount - always in the smallest unit of the currency
- * @param {String} currency
- * @param {String} created
- * @param {String} merchant
- * @param {String} payeeEmail
- * @param {Number} payeeAccountID
- * @param {Object} participant
- * @param {String} comment
- * @param {Object} [receipt]
- * @param {String} [category]
- * @param {String} [tag]
- * @param {String} [taxCode]
- * @param {Number} [taxAmount]
- * @param {Boolean} [billable]
- * @param {Object} [policy]
- * @param {Object} [policyTags]
- * @param {Object} [policyCategories]
+ * @param amount - always in the smallest unit of the currency
  */
 function requestMoney(
-    report,
-    amount,
-    currency,
-    created,
-    merchant,
-    payeeEmail,
-    payeeAccountID,
-    participant,
-    comment,
-    receipt = undefined,
-    category = undefined,
-    tag = undefined,
+    report: OnyxTypes.Report,
+    amount: number,
+    currency: string,
+    created: string,
+    merchant: string,
+    payeeEmail: string,
+    payeeAccountID: number,
+    participant: Participant,
+    comment: string,
+    receipt: Receipt,
+    category?: string,
+    tag?: string,
     taxCode = '',
     taxAmount = 0,
-    billable = undefined,
+    billable?: boolean,
     policy = undefined,
     policyTags = undefined,
     policyCategories = undefined,
@@ -1334,7 +1278,7 @@ function requestMoney(
     // If the report is iou or expense report, we should get the linked chat report to be passed to the getMoneyRequestInformation function
     const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report);
     const currentChatReport = isMoneyRequestReport ? ReportUtils.getReport(report.chatReportID) : report;
-    const moneyRequestReportID = isMoneyRequestReport ? report.reportID : 0;
+    const moneyRequestReportID = isMoneyRequestReport ? report.reportID : '';
     const currentCreated = DateUtils.enrichMoneyRequestTimestamp(created);
     const {payerAccountID, payerEmail, iouReport, chatReport, transaction, iouAction, createdChatReportActionID, createdIOUReportActionID, reportPreviewAction, onyxData} =
         getMoneyRequestInformation(
@@ -1345,8 +1289,6 @@ function requestMoney(
             currency,
             currentCreated,
             merchant,
-            payeeAccountID,
-            payeeEmail,
             receipt,
             undefined,
             category,
@@ -1355,37 +1297,37 @@ function requestMoney(
             policy,
             policyTags,
             policyCategories,
+            payeeAccountID,
+            payeeEmail,
             moneyRequestReportID,
         );
     const activeReportID = isMoneyRequestReport ? report.reportID : chatReport.reportID;
 
-    API.write(
-        'RequestMoney',
-        {
-            debtorEmail: payerEmail,
-            debtorAccountID: payerAccountID,
-            amount,
-            currency,
-            comment,
-            created: currentCreated,
-            merchant,
-            iouReportID: iouReport.reportID,
-            chatReportID: chatReport.reportID,
-            transactionID: transaction.transactionID,
-            reportActionID: iouAction.reportActionID,
-            createdChatReportActionID,
-            createdIOUReportActionID,
-            reportPreviewReportActionID: reportPreviewAction.reportActionID,
-            receipt,
-            receiptState: lodashGet(receipt, 'state'),
-            category,
-            tag,
-            taxCode,
-            taxAmount,
-            billable,
-        },
-        onyxData,
-    );
+    const parameters: RequestMoneyParams = {
+        debtorEmail: payerEmail,
+        debtorAccountID: payerAccountID,
+        amount,
+        currency,
+        comment,
+        created: currentCreated,
+        merchant,
+        iouReportID: iouReport.reportID,
+        chatReportID: chatReport.reportID,
+        transactionID: transaction.transactionID,
+        reportActionID: iouAction.reportActionID,
+        createdChatReportActionID,
+        createdIOUReportActionID,
+        reportPreviewReportActionID: reportPreviewAction.reportActionID,
+        receipt,
+        receiptState: receipt?.state,
+        category,
+        tag,
+        taxCode,
+        taxAmount,
+        billable,
+    };
+
+    API.write(WRITE_COMMANDS.REQUEST_MONEY, parameters, onyxData);
     resetMoneyRequestInfo();
     Navigation.dismissModal(activeReportID);
     Report.notifyNewAction(activeReportID, payeeAccountID);
@@ -1402,29 +1344,30 @@ function requestMoney(
  *      {email: 'user2', amount: 100, iouReportID: '100', chatReportID: '110', transactionID: '120', reportActionID: '130'},
  *      {email: 'user3', amount: 100, iouReportID: '200', chatReportID: '210', transactionID: '220', reportActionID: '230'}
  *  ]
- * @param {Array} participants
- * @param {String} currentUserLogin
- * @param {Number} currentUserAccountID
- * @param {Number} amount - always in the smallest unit of the currency
- * @param {String} comment
- * @param {String} currency
- * @param {String} merchant
- * @param {String} category
- * @param {String} tag
- * @param {String} existingSplitChatReportID - the report ID where the split bill happens, could be a group chat or a workspace chat
- * @param {Boolean} billable
- *
- * @return {Object}
- */
-function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag, existingSplitChatReportID = '', billable = false) {
+ * @param amount - always in the smallest unit of the currency
+ * @param existingSplitChatReportID - the report ID where the split bill happens, could be a group chat or a workspace chat
+ */
+function createSplitsAndOnyxData(
+    participants: Participant[],
+    currentUserLogin: string,
+    currentUserAccountID: number,
+    amount: number,
+    comment: string,
+    currency: string,
+    merchant: string,
+    category: string,
+    tag: string,
+    existingSplitChatReportID = '',
+    billable = false,
+): SplitsAndOnyxData {
     const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin);
-    const participantAccountIDs = _.map(participants, (participant) => Number(participant.accountID));
+    const participantAccountIDs = participants.map((participant) => Number(participant.accountID));
     const existingSplitChatReport =
         existingSplitChatReportID || participants[0].reportID
-            ? allReports[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`]
+            ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`]
             : ReportUtils.getChatByParticipants(participantAccountIDs);
-    const splitChatReport = existingSplitChatReport || ReportUtils.buildOptimisticChatReport(participantAccountIDs);
-    const isOwnPolicyExpenseChat = splitChatReport.isOwnPolicyExpenseChat;
+    const splitChatReport = existingSplitChatReport ?? ReportUtils.buildOptimisticChatReport(participantAccountIDs);
+    const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat;
 
     const splitTransaction = TransactionUtils.buildOptimisticTransaction(
         amount,
@@ -1452,7 +1395,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
         comment,
         participants,
         splitTransaction.transactionID,
-        '',
+        undefined,
         '',
         false,
         false,
@@ -1461,8 +1404,8 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
     );
 
     splitChatReport.lastReadTime = DateUtils.getDBTime();
-    splitChatReport.lastMessageText = splitIOUReportAction.message[0].text;
-    splitChatReport.lastMessageHtml = splitIOUReportAction.message[0].html;
+    splitChatReport.lastMessageText = splitIOUReportAction.message?.[0].text;
+    splitChatReport.lastMessageHtml = splitIOUReportAction.message?.[0].html;
 
     // If we have an existing splitChatReport (group chat or workspace) use it's pending fields, otherwise indicate that we are adding a chat
     if (!existingSplitChatReport) {
@@ -1471,7 +1414,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
         };
     }
 
-    const optimisticData = [
+    const optimisticData: OnyxUpdate[] = [
         {
             // Use set for new reports because it doesn't exist yet, is faster,
             // and we need the data to be available when we navigate to the chat page
@@ -1479,14 +1422,22 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
             key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`,
             value: splitChatReport,
         },
-        {
-            onyxMethod: existingSplitChatReport ? Onyx.METHOD.MERGE : Onyx.METHOD.SET,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
-            value: {
-                ...(existingSplitChatReport ? {} : {[splitCreatedReportAction.reportActionID]: splitCreatedReportAction}),
-                [splitIOUReportAction.reportActionID]: splitIOUReportAction,
-            },
-        },
+        existingSplitChatReport
+            ? {
+                  onyxMethod: Onyx.METHOD.MERGE,
+                  key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
+                  value: {
+                      [splitIOUReportAction.reportActionID]: splitIOUReportAction as OnyxTypes.ReportAction,
+                  },
+              }
+            : {
+                  onyxMethod: Onyx.METHOD.SET,
+                  key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
+                  value: {
+                      [splitCreatedReportAction.reportActionID]: splitCreatedReportAction as OnyxTypes.ReportAction,
+                      [splitIOUReportAction.reportActionID]: splitIOUReportAction as OnyxTypes.ReportAction,
+                  },
+              },
         {
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`,
@@ -1494,7 +1445,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
         },
     ];
 
-    const successData = [
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
@@ -1523,7 +1474,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
         });
     }
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`,
@@ -1573,16 +1524,16 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
 
     // Loop through participants creating individual chats, iouReports and reportActionIDs as needed
     const splitAmount = IOUUtils.calculateAmount(participants.length, amount, currency, false);
-    const splits = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, currency, true)}];
+    const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, currency, true)}];
 
     const hasMultipleParticipants = participants.length > 1;
-    _.each(participants, (participant) => {
+    participants.forEach((participant) => {
         // In a case when a participant is a workspace, even when a current user is not an owner of the workspace
         const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant);
 
         // In case the participant is a workspace, email & accountID should remain undefined and won't be used in the rest of this code
         // participant.login is undefined when the request is initiated from a group DM with an unknown user, so we need to add a default
-        const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || '').toLowerCase();
+        const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login ?? '').toLowerCase();
         const accountID = isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID);
         if (email === currentUserEmailForIOUSplit) {
             return;
@@ -1590,10 +1541,10 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
 
         // STEP 1: Get existing chat report OR build a new optimistic one
         // If we only have one participant and the request was initiated from the global create menu, i.e. !existingGroupChatReportID, the oneOnOneChatReport is the groupChatReport
-        let oneOnOneChatReport;
+        let oneOnOneChatReport: OptimisticChatReport;
         let isNewOneOnOneChatReport = false;
         let shouldCreateOptimisticPersonalDetails = false;
-        const personalDetailExists = lodashHas(allPersonalDetails, accountID);
+        const personalDetailExists = accountID in allPersonalDetails;
 
         // If this is a split between two people only and the function
         // wasn't provided with an existing group chat report id
@@ -1607,22 +1558,24 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
             const existingChatReport = ReportUtils.getChatByParticipants([accountID]);
             isNewOneOnOneChatReport = !existingChatReport;
             shouldCreateOptimisticPersonalDetails = isNewOneOnOneChatReport && !personalDetailExists;
-            oneOnOneChatReport = existingChatReport || ReportUtils.buildOptimisticChatReport([accountID]);
+            oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport([accountID]);
         }
 
         // STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one
         // For Control policy expense chats, if the report is already approved, create a new expense report
-        let oneOnOneIOUReport = oneOnOneChatReport.iouReportID ? lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined) : undefined;
+        let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null;
         const shouldCreateNewOneOnOneIOUReport =
-            _.isUndefined(oneOnOneIOUReport) || (isOwnPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport));
+            !oneOnOneIOUReport || (isOwnPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport));
 
-        if (shouldCreateNewOneOnOneIOUReport) {
+        if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) {
             oneOnOneIOUReport = isOwnPolicyExpenseChat
-                ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID, currentUserAccountID, splitAmount, currency)
+                ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, oneOnOneChatReport.policyID ?? '', currentUserAccountID, splitAmount, currency)
                 : ReportUtils.buildOptimisticIOUReport(currentUserAccountID, accountID, splitAmount, oneOnOneChatReport.reportID, currency);
         } else if (isOwnPolicyExpenseChat) {
-            // Because of the Expense reports are stored as negative values, we subtract the total from the amount
-            oneOnOneIOUReport.total -= splitAmount;
+            if (typeof oneOnOneIOUReport?.total === 'number') {
+                // Because of the Expense reports are stored as negative values, we subtract the total from the amount
+                oneOnOneIOUReport.total -= splitAmount;
+            }
         } else {
             oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, currentUserAccountID, splitAmount, currency);
         }
@@ -1661,7 +1614,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
             comment,
             [participant],
             oneOnOneTransaction.transactionID,
-            '',
+            undefined,
             oneOnOneIOUReport.reportID,
             undefined,
             undefined,
@@ -1671,17 +1624,19 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
         );
 
         // Add optimistic personal details for new participants
-        const oneOnOnePersonalDetailListAction = shouldCreateOptimisticPersonalDetails
+        const oneOnOnePersonalDetailListAction: OnyxTypes.PersonalDetailsList = shouldCreateOptimisticPersonalDetails
             ? {
                   [accountID]: {
                       accountID,
                       avatar: UserUtils.getDefaultAvatarURL(accountID),
+                      // Disabling this line since participant.displayName can be an empty string
+                      // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
                       displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || email),
                       login: participant.login,
                       isOptimisticPersonalDetail: true,
                   },
               }
-            : undefined;
+            : {};
 
         let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID);
         if (oneOnOneReportPreviewAction) {
@@ -1731,14 +1686,14 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
         failureData.push(...oneOnOneFailureData);
     });
 
-    const splitData = {
+    const splitData: SplitData = {
         chatReportID: splitChatReport.reportID,
         transactionID: splitTransaction.transactionID,
         reportActionID: splitIOUReportAction.reportActionID,
         policyID: splitChatReport.policyID,
     };
 
-    if (_.isEmpty(existingSplitChatReport)) {
+    if (!existingSplitChatReport) {
         splitData.createdReportActionID = splitCreatedReportAction.reportActionID;
     }
 
@@ -1750,19 +1705,22 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
 }
 
 /**
- * @param {Array} participants
- * @param {String} currentUserLogin
- * @param {Number} currentUserAccountID
- * @param {Number} amount - always in smallest currency unit
- * @param {String} comment
- * @param {String} currency
- * @param {String} merchant
- * @param {String} category
- * @param {String} tag
- * @param {String} existingSplitChatReportID - Either a group DM or a workspace chat
- * @param {Boolean} billable
- */
-function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag, existingSplitChatReportID = '', billable = false) {
+ * @param amount - always in smallest currency unit
+ * @param existingSplitChatReportID - Either a group DM or a workspace chat
+ */
+function splitBill(
+    participants: Participant[],
+    currentUserLogin: string,
+    currentUserAccountID: number,
+    amount: number,
+    comment: string,
+    currency: string,
+    merchant: string,
+    category: string,
+    tag: string,
+    existingSplitChatReportID = '',
+    billable = false,
+) {
     const {splitData, splits, onyxData} = createSplitsAndOnyxData(
         participants,
         currentUserLogin,
@@ -1776,65 +1734,64 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount,
         existingSplitChatReportID,
         billable,
     );
-    API.write(
-        'SplitBill',
-        {
-            reportID: splitData.chatReportID,
-            amount,
-            splits: JSON.stringify(splits),
-            currency,
-            comment,
-            category,
-            merchant,
-            tag,
-            billable,
-            transactionID: splitData.transactionID,
-            reportActionID: splitData.reportActionID,
-            createdReportActionID: splitData.createdReportActionID,
-            policyID: splitData.policyID,
-        },
-        onyxData,
-    );
-
-    resetMoneyRequestInfo();
-    Navigation.dismissModal();
-    Report.notifyNewAction(splitData.chatReportID, currentUserAccountID);
-}
 
-/**
- * @param {Array} participants
- * @param {String} currentUserLogin
- * @param {Number} currentUserAccountID
- * @param {Number} amount - always in smallest currency unit
- * @param {String} comment
- * @param {String} currency
- * @param {String} merchant
- * @param {String} category
- * @param {String} tag
- * @param {Boolean} billable
- */
-function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag, billable) {
-    const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag, billable);
+    const parameters: SplitBillParams = {
+        reportID: splitData.chatReportID,
+        amount,
+        splits: JSON.stringify(splits),
+        currency,
+        comment,
+        category,
+        merchant,
+        tag,
+        billable,
+        transactionID: splitData.transactionID,
+        reportActionID: splitData.reportActionID,
+        createdReportActionID: splitData.createdReportActionID,
+        policyID: splitData.policyID,
+    };
 
-    API.write(
-        'SplitBillAndOpenReport',
-        {
-            reportID: splitData.chatReportID,
-            amount,
-            splits: JSON.stringify(splits),
-            currency,
-            merchant,
-            comment,
-            category,
-            tag,
-            billable,
-            transactionID: splitData.transactionID,
-            reportActionID: splitData.reportActionID,
-            createdReportActionID: splitData.createdReportActionID,
-            policyID: splitData.policyID,
-        },
-        onyxData,
-    );
+    API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData);
+
+    resetMoneyRequestInfo();
+    Navigation.dismissModal();
+    Report.notifyNewAction(splitData.chatReportID, currentUserAccountID);
+}
+
+/**
+ * @param amount - always in smallest currency unit
+ */
+function splitBillAndOpenReport(
+    participants: Participant[],
+    currentUserLogin: string,
+    currentUserAccountID: number,
+    amount: number,
+    comment: string,
+    currency: string,
+    merchant: string,
+    category: string,
+    tag: string,
+    billable: boolean,
+) {
+    const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, merchant, category, tag);
+
+    const parameters: SplitBillParams = {
+        reportID: splitData.chatReportID,
+        amount,
+        splits: JSON.stringify(splits),
+        currency,
+        merchant,
+        comment,
+        category,
+        tag,
+        billable,
+        transactionID: splitData.transactionID,
+        reportActionID: splitData.reportActionID,
+        createdReportActionID: splitData.createdReportActionID,
+        policyID: splitData.policyID,
+    };
+
+    API.write(WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT, parameters, onyxData);
 
     resetMoneyRequestInfo();
     Navigation.dismissModal(splitData.chatReportID);
@@ -1844,28 +1801,30 @@ function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccou
 /** Used exclusively for starting a split bill request that contains a receipt, the split request will be completed once the receipt is scanned
  *  or user enters details manually.
  *
- * @param {Array} participants
- * @param {String} currentUserLogin
- * @param {Number} currentUserAccountID
- * @param {String} comment
- * @param {String} category
- * @param {String} tag
- * @param {Object} receipt
- * @param {String} existingSplitChatReportID - Either a group DM or a workspace chat
- * @param {Boolean} billable
- */
-function startSplitBill(participants, currentUserLogin, currentUserAccountID, comment, category, tag, receipt, existingSplitChatReportID = '', billable = false) {
+ * @param existingSplitChatReportID - Either a group DM or a workspace chat
+ */
+function startSplitBill(
+    participants: Participant[],
+    currentUserLogin: string,
+    currentUserAccountID: number,
+    comment: string,
+    category: string,
+    tag: string,
+    receipt: Receipt,
+    existingSplitChatReportID = '',
+    billable = false,
+) {
     const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin);
-    const participantAccountIDs = _.map(participants, (participant) => Number(participant.accountID));
+    const participantAccountIDs = participants.map((participant) => Number(participant.accountID));
     const existingSplitChatReport =
         existingSplitChatReportID || participants[0].reportID
-            ? allReports[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`]
+            ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`]
             : ReportUtils.getChatByParticipants(participantAccountIDs);
-    const splitChatReport = existingSplitChatReport || ReportUtils.buildOptimisticChatReport(participantAccountIDs);
-    const isOwnPolicyExpenseChat = splitChatReport.isOwnPolicyExpenseChat || false;
+    const splitChatReport = existingSplitChatReport ?? ReportUtils.buildOptimisticChatReport(participantAccountIDs);
+    const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat;
 
     const {name: filename, source, state = CONST.IOU.RECEIPT_STATE.SCANREADY} = receipt;
-    const receiptObject = {state, source};
+    const receiptObject: Receipt = {state, source};
 
     // ReportID is -2 (aka "deleted") on the group transaction
     const splitTransaction = TransactionUtils.buildOptimisticTransaction(
@@ -1894,7 +1853,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
         comment,
         participants,
         splitTransaction.transactionID,
-        '',
+        undefined,
         '',
         false,
         false,
@@ -1903,8 +1862,8 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
     );
 
     splitChatReport.lastReadTime = DateUtils.getDBTime();
-    splitChatReport.lastMessageText = splitIOUReportAction.message[0].text;
-    splitChatReport.lastMessageHtml = splitIOUReportAction.message[0].html;
+    splitChatReport.lastMessageText = splitIOUReportAction.message?.[0].text;
+    splitChatReport.lastMessageHtml = splitIOUReportAction.message?.[0].html;
 
     // If we have an existing splitChatReport (group chat or workspace) use it's pending fields, otherwise indicate that we are adding a chat
     if (!existingSplitChatReport) {
@@ -1913,7 +1872,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
         };
     }
 
-    const optimisticData = [
+    const optimisticData: OnyxUpdate[] = [
         {
             // Use set for new reports because it doesn't exist yet, is faster,
             // and we need the data to be available when we navigate to the chat page
@@ -1921,14 +1880,22 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
             key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`,
             value: splitChatReport,
         },
-        {
-            onyxMethod: existingSplitChatReport ? Onyx.METHOD.MERGE : Onyx.METHOD.SET,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
-            value: {
-                ...(existingSplitChatReport ? {} : {[splitChatCreatedReportAction.reportActionID]: splitChatCreatedReportAction}),
-                [splitIOUReportAction.reportActionID]: splitIOUReportAction,
-            },
-        },
+        existingSplitChatReport
+            ? {
+                  onyxMethod: Onyx.METHOD.MERGE,
+                  key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
+                  value: {
+                      [splitIOUReportAction.reportActionID]: splitIOUReportAction as OnyxTypes.ReportAction,
+                  },
+              }
+            : {
+                  onyxMethod: Onyx.METHOD.SET,
+                  key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
+                  value: {
+                      [splitChatCreatedReportAction.reportActionID]: splitChatCreatedReportAction,
+                      [splitIOUReportAction.reportActionID]: splitIOUReportAction as OnyxTypes.ReportAction,
+                  },
+              },
         {
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`,
@@ -1936,7 +1903,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
         },
     ];
 
-    const successData = [
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
@@ -1960,7 +1927,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
         });
     }
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`,
@@ -2006,10 +1973,12 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
         );
     }
 
-    const splits = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}];
+    const splits: Split[] = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}];
 
-    _.each(participants, (participant) => {
-        const email = participant.isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || participant.text).toLowerCase();
+    participants.forEach((participant) => {
+        // Disabling this line since participant.login can be an empty string
+        // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+        const email = participant.isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || participant.text || '').toLowerCase();
         const accountID = participant.isOwnPolicyExpenseChat ? 0 : Number(participant.accountID);
         if (email === currentUserEmailForIOUSplit) {
             return;
@@ -2024,7 +1993,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
             return;
         }
 
-        const participantPersonalDetails = allPersonalDetails[participant.accountID];
+        const participantPersonalDetails = allPersonalDetails[participant?.accountID ?? -1];
         if (!participantPersonalDetails) {
             optimisticData.push({
                 onyxMethod: Onyx.METHOD.MERGE,
@@ -2033,7 +2002,11 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
                     [accountID]: {
                         accountID,
                         avatar: UserUtils.getDefaultAvatarURL(accountID),
+                        // Disabling this line since participant.displayName can be an empty string
+                        // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
                         displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || email),
+                        // Disabling this line since participant.login can be an empty string
+                        // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
                         login: participant.login || participant.text,
                         isOptimisticPersonalDetail: true,
                     },
@@ -2047,7 +2020,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
         });
     });
 
-    _.each(participants, (participant) => {
+    participants.forEach((participant) => {
         const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant);
         if (!isPolicyExpenseChat) {
             return;
@@ -2056,7 +2029,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
         const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category);
         const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag);
 
-        if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) {
+        if (optimisticPolicyRecentlyUsedCategories.length > 0) {
             optimisticData.push({
                 onyxMethod: Onyx.METHOD.SET,
                 key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${participant.policyID}`,
@@ -2064,7 +2037,7 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
             });
         }
 
-        if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) {
+        if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) {
             optimisticData.push({
                 onyxMethod: Onyx.METHOD.MERGE,
                 key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${participant.policyID}`,
@@ -2084,44 +2057,42 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co
         },
     });
 
-    API.write(
-        'StartSplitBill',
-        {
-            chatReportID: splitChatReport.reportID,
-            reportActionID: splitIOUReportAction.reportActionID,
-            transactionID: splitTransaction.transactionID,
-            splits: JSON.stringify(splits),
-            receipt,
-            comment,
-            category,
-            tag,
-            isFromGroupDM: !existingSplitChatReport,
-            billable,
-            ...(existingSplitChatReport ? {} : {createdReportActionID: splitChatCreatedReportAction.reportActionID}),
-        },
-        {optimisticData, successData, failureData},
-    );
+    const parameters: StartSplitBillParams = {
+        chatReportID: splitChatReport.reportID,
+        reportActionID: splitIOUReportAction.reportActionID,
+        transactionID: splitTransaction.transactionID,
+        splits: JSON.stringify(splits),
+        receipt,
+        comment,
+        category,
+        tag,
+        isFromGroupDM: !existingSplitChatReport,
+        billable,
+        ...(existingSplitChatReport ? {} : {createdReportActionID: splitChatCreatedReportAction.reportActionID}),
+    };
+
+    API.write(WRITE_COMMANDS.START_SPLIT_BILL, parameters, {optimisticData, successData, failureData});
 
     resetMoneyRequestInfo();
     Navigation.dismissModalWithReport(splitChatReport);
-    Report.notifyNewAction(splitChatReport.chatReportID, currentUserAccountID);
+    Report.notifyNewAction(splitChatReport.chatReportID ?? '', currentUserAccountID);
 }
 
 /** Used for editing a split bill while it's still scanning or when SmartScan fails, it completes a split bill started by startSplitBill above.
  *
- * @param {number} chatReportID - The group chat or workspace reportID
- * @param {Object} reportAction - The split action that lives in the chatReport above
- * @param {Object} updatedTransaction - The updated **draft** split transaction
- * @param {Number} sessionAccountID - accountID of the current user
- * @param {String} sessionEmail - email of the current user
+ * @param chatReportID - The group chat or workspace reportID
+ * @param reportAction - The split action that lives in the chatReport above
+ * @param updatedTransaction - The updated **draft** split transaction
+ * @param sessionAccountID - accountID of the current user
+ * @param sessionEmail - email of the current user
  */
-function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessionAccountID, sessionEmail) {
+function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportAction, updatedTransaction: OnyxTypes.Transaction, sessionAccountID: number, sessionEmail: string) {
     const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(sessionEmail);
     const {transactionID} = updatedTransaction;
     const unmodifiedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
 
     // Save optimistic updated transaction and action
-    const optimisticData = [
+    const optimisticData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
@@ -2144,7 +2115,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi
         },
     ];
 
-    const successData = [
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
@@ -2153,11 +2124,11 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`,
-            value: null,
+            value: {pendingAction: null},
         },
     ];
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
@@ -2178,25 +2149,25 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi
         },
     ];
 
-    const splitParticipants = updatedTransaction.comment.splits;
+    const splitParticipants: Split[] = updatedTransaction.comment.splits ?? [];
     const {modifiedAmount: amount, modifiedCurrency: currency} = updatedTransaction;
 
     // Exclude the current user when calculating the split amount, `calculateAmount` takes it into account
-    const splitAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, amount, currency, false);
+    const splitAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, amount ?? 0, currency ?? '', false);
 
-    const splits = [{email: currentUserEmailForIOUSplit}];
-    _.each(splitParticipants, (participant) => {
+    const splits: Split[] = [{email: currentUserEmailForIOUSplit}];
+    splitParticipants.forEach((participant) => {
         // Skip creating the transaction for the current user
         if (participant.email === currentUserEmailForIOUSplit) {
             return;
         }
-        const isPolicyExpenseChat = !_.isEmpty(participant.policyID);
+        const isPolicyExpenseChat = !!participant.policyID;
 
         if (!isPolicyExpenseChat) {
             // In case this is still the optimistic accountID saved in the splits array, return early as we cannot know
             // if there is an existing chat between the split creator and this participant
             // Instead, we will rely on Auth generating the report IDs and the user won't see any optimistic chats or reports created
-            const participantPersonalDetails = allPersonalDetails[participant.accountID] || {};
+            const participantPersonalDetails: OnyxTypes.PersonalDetails | EmptyObject = allPersonalDetails[participant?.accountID ?? -1] ?? {};
             if (!participantPersonalDetails || participantPersonalDetails.isOptimisticPersonalDetail) {
                 splits.push({
                     email: participant.email,
@@ -2205,36 +2176,38 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi
             }
         }
 
-        let oneOnOneChatReport;
+        let oneOnOneChatReport: OnyxTypes.Report | null;
         let isNewOneOnOneChatReport = false;
         if (isPolicyExpenseChat) {
             // The workspace chat reportID is saved in the splits array when starting a split bill with a workspace
-            oneOnOneChatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`];
+            oneOnOneChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`] ?? null;
         } else {
-            const existingChatReport = ReportUtils.getChatByParticipants([participant.accountID]);
+            const existingChatReport = ReportUtils.getChatByParticipants(participant.accountID ? [participant.accountID] : []);
             isNewOneOnOneChatReport = !existingChatReport;
-            oneOnOneChatReport = existingChatReport || ReportUtils.buildOptimisticChatReport([participant.accountID]);
+            oneOnOneChatReport = existingChatReport ?? ReportUtils.buildOptimisticChatReport(participant.accountID ? [participant.accountID] : []);
         }
 
-        let oneOnOneIOUReport = oneOnOneChatReport.iouReportID ? lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined) : undefined;
+        let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null;
         const shouldCreateNewOneOnOneIOUReport =
-            _.isUndefined(oneOnOneIOUReport) || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport));
+            !oneOnOneIOUReport || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport));
 
-        if (shouldCreateNewOneOnOneIOUReport) {
+        if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) {
             oneOnOneIOUReport = isPolicyExpenseChat
-                ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, participant.policyID, sessionAccountID, splitAmount, currency)
-                : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID, splitAmount, oneOnOneChatReport.reportID, currency);
+                ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport?.reportID ?? '', participant.policyID ?? '', sessionAccountID, splitAmount, currency ?? '')
+                : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID ?? -1, splitAmount, oneOnOneChatReport?.reportID ?? '', currency ?? '');
         } else if (isPolicyExpenseChat) {
-            // Because of the Expense reports are stored as negative values, we subtract the total from the amount
-            oneOnOneIOUReport.total -= splitAmount;
+            if (typeof oneOnOneIOUReport?.total === 'number') {
+                // Because of the Expense reports are stored as negative values, we subtract the total from the amount
+                oneOnOneIOUReport.total -= splitAmount;
+            }
         } else {
-            oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, sessionAccountID, splitAmount, currency);
+            oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, sessionAccountID, splitAmount, currency ?? '');
         }
 
         const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction(
             isPolicyExpenseChat ? -splitAmount : splitAmount,
-            currency,
-            oneOnOneIOUReport.reportID,
+            currency ?? '',
+            oneOnOneIOUReport?.reportID ?? '',
             updatedTransaction.comment.comment,
             updatedTransaction.modifiedCreated,
             CONST.IOU.TYPE.SPLIT,
@@ -2249,15 +2222,15 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi
         const oneOnOneIOUAction = ReportUtils.buildOptimisticIOUReportAction(
             CONST.IOU.REPORT_ACTION_TYPE.CREATE,
             splitAmount,
-            currency,
-            updatedTransaction.comment.comment,
+            currency ?? '',
+            updatedTransaction.comment.comment ?? '',
             [participant],
             oneOnOneTransaction.transactionID,
-            '',
-            oneOnOneIOUReport.reportID,
+            undefined,
+            oneOnOneIOUReport?.reportID,
         );
 
-        let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID);
+        let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport?.reportID ?? '', oneOnOneIOUReport?.reportID ?? '');
         if (oneOnOneReportPreviewAction) {
             oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction);
         } else {
@@ -2273,7 +2246,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi
             oneOnOneIOUAction,
             {},
             oneOnOneReportPreviewAction,
-            {},
+            [],
             {},
             isNewOneOnOneChatReport,
             shouldCreateNewOneOnOneIOUReport,
@@ -2283,8 +2256,8 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi
             email: participant.email,
             accountID: participant.accountID,
             policyID: participant.policyID,
-            iouReportID: oneOnOneIOUReport.reportID,
-            chatReportID: oneOnOneChatReport.reportID,
+            iouReportID: oneOnOneIOUReport?.reportID,
+            chatReportID: oneOnOneChatReport?.reportID,
             transactionID: oneOnOneTransaction.transactionID,
             reportActionID: oneOnOneIOUAction.reportActionID,
             createdChatReportActionID: oneOnOneCreatedActionForChat.reportActionID,
@@ -2305,59 +2278,48 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi
         comment: transactionComment,
         category: transactionCategory,
         tag: transactionTag,
-    } = ReportUtils.getTransactionDetails(updatedTransaction);
+    } = ReportUtils.getTransactionDetails(updatedTransaction) ?? {};
 
-    API.write(
-        'CompleteSplitBill',
-        {
-            transactionID,
-            amount: transactionAmount,
-            currency: transactionCurrency,
-            created: transactionCreated,
-            merchant: transactionMerchant,
-            comment: transactionComment,
-            category: transactionCategory,
-            tag: transactionTag,
-            splits: JSON.stringify(splits),
-        },
-        {optimisticData, successData, failureData},
-    );
+    const parameters: CompleteSplitBillParams = {
+        transactionID,
+        amount: transactionAmount,
+        currency: transactionCurrency,
+        created: transactionCreated,
+        merchant: transactionMerchant,
+        comment: transactionComment,
+        category: transactionCategory,
+        tag: transactionTag,
+        splits: JSON.stringify(splits),
+    };
+
+    API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData});
     Navigation.dismissModal(chatReportID);
     Report.notifyNewAction(chatReportID, sessionAccountID);
 }
 
-/**
- * @param {String} transactionID
- * @param {Object} transactionChanges
- */
-function setDraftSplitTransaction(transactionID, transactionChanges = {}) {
+function setDraftSplitTransaction(transactionID: string, transactionChanges: TransactionChanges = {}) {
     let draftSplitTransaction = allDraftSplitTransactions[`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`];
 
     if (!draftSplitTransaction) {
         draftSplitTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
     }
 
-    const updatedTransaction = TransactionUtils.getUpdatedTransaction(draftSplitTransaction, transactionChanges, false, false);
+    const updatedTransaction = draftSplitTransaction ? TransactionUtils.getUpdatedTransaction(draftSplitTransaction, transactionChanges, false, false) : null;
 
     Onyx.merge(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, updatedTransaction);
 }
 
-/**
- * @param {String} transactionID
- * @param {Number} transactionThreadReportID
- * @param {Object} transactionChanges
- */
-function editRegularMoneyRequest(transactionID, transactionThreadReportID, transactionChanges) {
+function editRegularMoneyRequest(transactionID: string, transactionThreadReportID: string, transactionChanges: TransactionChanges) {
     // STEP 1: Get all collections we're updating
-    const transactionThread = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`];
+    const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null;
     const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
-    const iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread.parentReportID}`];
-    const chatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${iouReport.chatReportID}`];
+    const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread?.parentReportID}`] ?? null;
+    const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`] ?? null;
     const isFromExpenseReport = ReportUtils.isExpenseReport(iouReport);
 
     // STEP 2: Build new modified expense report action.
     const updatedReportAction = ReportUtils.buildOptimisticModifiedExpenseReportAction(transactionThread, transaction, transactionChanges, isFromExpenseReport);
-    const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport);
+    const updatedTransaction = transaction ? TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport) : null;
 
     // STEP 3: Compute the IOU total and update the report preview message so LHN amount owed is correct
     // Should only update if the transaction matches the currency of the report, else we wait for the update
@@ -2365,20 +2327,22 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans
     let updatedMoneyRequestReport = {...iouReport};
     const updatedChatReport = {...chatReport};
     const diff = TransactionUtils.getAmount(transaction, true) - TransactionUtils.getAmount(updatedTransaction, true);
-    if (updatedTransaction.currency === iouReport.currency && updatedTransaction.modifiedAmount && diff !== 0) {
-        if (ReportUtils.isExpenseReport(iouReport)) {
+    if (updatedTransaction?.currency === iouReport?.currency && updatedTransaction?.modifiedAmount && diff !== 0) {
+        if (ReportUtils.isExpenseReport(iouReport) && typeof updatedMoneyRequestReport.total === 'number') {
             updatedMoneyRequestReport.total += diff;
         } else {
-            updatedMoneyRequestReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID, diff, TransactionUtils.getCurrency(transaction), false);
+            updatedMoneyRequestReport = iouReport
+                ? IOUUtils.updateIOUOwnerAndTotal(iouReport, updatedReportAction.actorAccountID ?? -1, diff, TransactionUtils.getCurrency(transaction), false)
+                : {};
         }
 
         updatedMoneyRequestReport.cachedTotal = CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedTransaction.currency);
 
         // Update the last message of the IOU report
         const lastMessage = ReportUtils.getIOUReportActionMessage(
-            iouReport.reportID,
+            iouReport?.reportID ?? '',
             CONST.IOU.REPORT_ACTION_TYPE.CREATE,
-            updatedMoneyRequestReport.total,
+            updatedMoneyRequestReport.total ?? 0,
             '',
             updatedTransaction.currency,
             '',
@@ -2388,9 +2352,9 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans
         updatedMoneyRequestReport.lastMessageHtml = lastMessage[0].html;
 
         // Update the last message of the chat report
-        const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport);
+        const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID);
         const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', {
-            payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID).login || '',
+            payer: ReportUtils.getPersonalDetailsForAccountID(updatedMoneyRequestReport.managerID ?? -1).login ?? '',
             amount: CurrencyUtils.convertToDisplayString(updatedMoneyRequestReport.total, updatedMoneyRequestReport.currency),
         });
         updatedChatReport.lastMessageText = messageText;
@@ -2401,12 +2365,12 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans
 
     // STEP 4: Compose the optimistic data
     const currentTime = DateUtils.getDBTime();
-    const optimisticData = [
+    const optimisticData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`,
             value: {
-                [updatedReportAction.reportActionID]: updatedReportAction,
+                [updatedReportAction.reportActionID]: updatedReportAction as OnyxTypes.ReportAction,
             },
         },
         {
@@ -2416,12 +2380,12 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
             value: updatedMoneyRequestReport,
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.chatReportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`,
             value: updatedChatReport,
         },
         {
@@ -2432,58 +2396,59 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans
                 lastVisibleActionCreated: currentTime,
             },
         },
-        ...(!isScanning
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
-                      value: {
-                          [transactionThread.parentReportActionID]: {
-                              whisperedToAccountIDs: [],
-                          },
-                      },
-                  },
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`,
-                      value: {
-                          [iouReport.parentReportActionID]: {
-                              whisperedToAccountIDs: [],
-                          },
-                      },
-                  },
-              ]
-            : []),
     ];
 
+    if (!isScanning) {
+        optimisticData.push(
+            {
+                onyxMethod: Onyx.METHOD.MERGE,
+                key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
+                value: {
+                    [transactionThread?.parentReportActionID ?? '']: {
+                        whisperedToAccountIDs: [],
+                    },
+                },
+            },
+            {
+                onyxMethod: Onyx.METHOD.MERGE,
+                key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.parentReportID}`,
+                value: {
+                    [iouReport?.parentReportActionID ?? '']: {
+                        whisperedToAccountIDs: [],
+                    },
+                },
+            },
+        );
+    }
+
     // Update recently used categories if the category is changed
-    if (_.has(transactionChanges, 'category')) {
-        const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, transactionChanges.category);
-        if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) {
+    if ('category' in transactionChanges) {
+        const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport?.policyID, transactionChanges.category);
+        if (optimisticPolicyRecentlyUsedCategories.length) {
             optimisticData.push({
                 onyxMethod: Onyx.METHOD.SET,
-                key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`,
+                key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport?.policyID}`,
                 value: optimisticPolicyRecentlyUsedCategories,
             });
         }
     }
 
     // Update recently used categories if the tag is changed
-    if (_.has(transactionChanges, 'tag')) {
-        const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport.policyID, transactionChanges.tag);
-        if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) {
+    if ('tag' in transactionChanges) {
+        const optimisticPolicyRecentlyUsedTags = Policy.buildOptimisticPolicyRecentlyUsedTags(iouReport?.policyID, transactionChanges.tag);
+        if (!isEmptyObject(optimisticPolicyRecentlyUsedTags)) {
             optimisticData.push({
                 onyxMethod: Onyx.METHOD.MERGE,
-                key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport.policyID}`,
+                key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${iouReport?.policyID}`,
                 value: optimisticPolicyRecentlyUsedTags,
             });
         }
     }
 
-    const successData = [
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`,
             value: {
                 [updatedReportAction.reportActionID]: {pendingAction: null},
             },
@@ -2506,15 +2471,15 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
             value: {pendingAction: null},
         },
     ];
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`,
             value: {
                 [updatedReportAction.reportActionID]: {
                     errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericEditFailureMessage'),
@@ -2526,63 +2491,57 @@ function editRegularMoneyRequest(transactionID, transactionThreadReportID, trans
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
             value: {
                 ...transaction,
-                modifiedCreated: transaction.modifiedCreated ? transaction.modifiedCreated : null,
-                modifiedAmount: transaction.modifiedAmount ? transaction.modifiedAmount : null,
-                modifiedCurrency: transaction.modifiedCurrency ? transaction.modifiedCurrency : null,
-                modifiedMerchant: transaction.modifiedMerchant ? transaction.modifiedMerchant : null,
-                modifiedWaypoints: transaction.modifiedWaypoints ? transaction.modifiedWaypoints : null,
+                modifiedCreated: transaction?.modifiedCreated ? transaction.modifiedCreated : null,
+                modifiedAmount: transaction?.modifiedAmount ? transaction.modifiedAmount : null,
+                modifiedCurrency: transaction?.modifiedCurrency ? transaction.modifiedCurrency : null,
+                modifiedMerchant: transaction?.modifiedMerchant ? transaction.modifiedMerchant : null,
+                modifiedWaypoints: transaction?.modifiedWaypoints ? transaction.modifiedWaypoints : null,
                 pendingFields: null,
             },
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
             value: {
                 ...iouReport,
-                cachedTotal: iouReport.cachedTotal ? iouReport.cachedTotal : null,
+                cachedTotal: iouReport?.cachedTotal ? iouReport?.cachedTotal : null,
             },
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.chatReportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`,
             value: chatReport,
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`,
             value: {
-                lastReadTime: transactionThread.lastReadTime,
-                lastVisibleActionCreated: transactionThread.lastVisibleActionCreated,
+                lastReadTime: transactionThread?.lastReadTime,
+                lastVisibleActionCreated: transactionThread?.lastVisibleActionCreated,
             },
         },
     ];
 
     // STEP 6: Call the API endpoint
-    const {created, amount, currency, comment, merchant, category, billable, tag} = ReportUtils.getTransactionDetails(updatedTransaction);
-    API.write(
-        'EditMoneyRequest',
-        {
-            transactionID,
-            reportActionID: updatedReportAction.reportActionID,
-            created,
-            amount,
-            currency,
-            comment,
-            merchant,
-            category,
-            billable,
-            tag,
-        },
-        {optimisticData, successData, failureData},
-    );
+    const {created, amount, currency, comment, merchant, category, billable, tag} = ReportUtils.getTransactionDetails(updatedTransaction) ?? {};
+
+    const parameters: EditMoneyRequestParams = {
+        transactionID,
+        reportActionID: updatedReportAction.reportActionID,
+        created,
+        amount,
+        currency,
+        comment,
+        merchant,
+        category,
+        billable,
+        tag,
+    };
+
+    API.write(WRITE_COMMANDS.EDIT_MONEY_REQUEST, parameters, {optimisticData, successData, failureData});
 }
 
-/**
- * @param {object} transaction
- * @param {String} transactionThreadReportID
- * @param {Object} transactionChanges
- */
-function editMoneyRequest(transaction, transactionThreadReportID, transactionChanges) {
+function editMoneyRequest(transaction: OnyxTypes.Transaction, transactionThreadReportID: string, transactionChanges: TransactionChanges) {
     if (TransactionUtils.isDistanceRequest(transaction)) {
         updateDistanceRequest(transaction.transactionID, transactionThreadReportID, transactionChanges);
     } else {
@@ -2590,46 +2549,35 @@ function editMoneyRequest(transaction, transactionThreadReportID, transactionCha
     }
 }
 
-/**
- * Updates the amount and currency fields of a money request
- *
- * @param {String} transactionID
- * @param {String} transactionThreadReportID
- * @param {String} currency
- * @param {Number} amount
- */
-function updateMoneyRequestAmountAndCurrency(transactionID, transactionThreadReportID, currency, amount) {
+/** Updates the amount and currency fields of a money request */
+function updateMoneyRequestAmountAndCurrency(transactionID: string, transactionThreadReportID: string, currency: string, amount: number) {
     const transactionChanges = {
         amount,
         currency,
     };
     const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true);
-    API.write('UpdateMoneyRequestAmountAndCurrency', params, onyxData);
+    API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY, params, onyxData);
 }
 
-/**
- * @param {String | undefined} transactionID
- * @param {Object} reportAction - the money request reportAction we are deleting
- * @param {Boolean} isSingleTransactionView
- */
-function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView = false) {
+function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
     // STEP 1: Get all collections we're updating
-    const iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${reportAction.originalMessage.IOUReportID}`];
-    const chatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${iouReport.chatReportID}`];
-    const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(iouReport.chatReportID, iouReport.reportID);
+    const iouReportID = reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? reportAction.originalMessage.IOUReportID : '';
+    const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null;
+    const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`];
+    const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(iouReport?.chatReportID ?? '', iouReport?.reportID ?? '');
     const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
     const transactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`];
     const transactionThreadID = reportAction.childReportID;
     let transactionThread = null;
     if (transactionThreadID) {
-        transactionThread = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`];
+        transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`] ?? null;
     }
 
     // STEP 2: Decide if we need to:
     // 1. Delete the transactionThread - delete if there are no visible comments in the thread
     // 2. Update the moneyRequestPreview to show [Deleted request] - update if the transactionThread exists AND it isn't being deleted
-    const shouldDeleteTransactionThread = transactionThreadID ? lodashGet(reportAction, 'childVisibleActionCount', 0) === 0 : false;
-    const shouldShowDeletedRequestMessage = transactionThreadID && !shouldDeleteTransactionThread;
+    const shouldDeleteTransactionThread = transactionThreadID ? (reportAction?.childVisibleActionCount ?? 0) === 0 : false;
+    const shouldShowDeletedRequestMessage = !!transactionThreadID && !shouldDeleteTransactionThread;
 
     // STEP 3: Update the IOU reportAction and decide if the iouReport should be deleted. We delete the iouReport if there are no visible comments left in the report.
     const updatedReportAction = {
@@ -2648,127 +2596,135 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView
             originalMessage: {
                 IOUTransactionID: null,
             },
-            errors: null,
+            errors: undefined,
         },
-    };
+    } as OnyxTypes.ReportActions;
 
-    const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(iouReport.reportID, updatedReportAction);
-    const iouReportLastMessageText = ReportActionsUtils.getLastVisibleMessage(iouReport.reportID, updatedReportAction).lastMessageText;
+    const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(iouReport?.reportID ?? '', updatedReportAction);
+    const iouReportLastMessageText = ReportActionsUtils.getLastVisibleMessage(iouReport?.reportID ?? '', updatedReportAction).lastMessageText;
     const shouldDeleteIOUReport =
         iouReportLastMessageText.length === 0 && !ReportActionsUtils.isDeletedParentAction(lastVisibleAction) && (!transactionThreadID || shouldDeleteTransactionThread);
 
     // STEP 4: Update the iouReport and reportPreview with new totals and messages if it wasn't deleted
-    let updatedIOUReport = {...iouReport};
-    const updatedReportPreviewAction = {...reportPreviewAction};
+    let updatedIOUReport: OnyxTypes.Report | null;
+    const updatedReportPreviewAction: OnyxTypes.ReportAction | EmptyObject = {...reportPreviewAction};
     updatedReportPreviewAction.pendingAction = shouldDeleteIOUReport ? CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE;
-    if (ReportUtils.isExpenseReport(iouReport)) {
+    if (iouReport && ReportUtils.isExpenseReport(iouReport)) {
         updatedIOUReport = {...iouReport};
 
-        // Because of the Expense reports are stored as negative values, we add the total from the amount
-        updatedIOUReport.total += TransactionUtils.getAmount(transaction, true);
+        if (typeof updatedIOUReport.total === 'number') {
+            // Because of the Expense reports are stored as negative values, we add the total from the amount
+            updatedIOUReport.total += TransactionUtils.getAmount(transaction, true);
+        }
     } else {
         updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal(
             iouReport,
-            reportAction.actorAccountID,
+            reportAction.actorAccountID ?? -1,
             TransactionUtils.getAmount(transaction, false),
             TransactionUtils.getCurrency(transaction),
             true,
         );
     }
 
-    updatedIOUReport.lastMessageText = iouReportLastMessageText;
-    updatedIOUReport.lastVisibleActionCreated = lodashGet(lastVisibleAction, 'created');
+    if (updatedIOUReport) {
+        updatedIOUReport.lastMessageText = iouReportLastMessageText;
+        updatedIOUReport.lastVisibleActionCreated = lastVisibleAction?.created;
+    }
 
-    const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport);
+    const hasNonReimbursableTransactions = ReportUtils.hasNonReimbursableTransactions(iouReport?.reportID);
     const messageText = Localize.translateLocal(hasNonReimbursableTransactions ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', {
-        payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport.managerID).login || '',
-        amount: CurrencyUtils.convertToDisplayString(updatedIOUReport.total, updatedIOUReport.currency),
+        payer: ReportUtils.getPersonalDetailsForAccountID(updatedIOUReport?.managerID ?? -1).login ?? '',
+        amount: CurrencyUtils.convertToDisplayString(updatedIOUReport?.total, updatedIOUReport?.currency),
     });
-    updatedReportPreviewAction.message[0].text = messageText;
-    updatedReportPreviewAction.message[0].html = shouldDeleteIOUReport ? '' : messageText;
 
-    if (reportPreviewAction.childMoneyRequestCount > 0) {
+    if (updatedReportPreviewAction?.message?.[0]) {
+        updatedReportPreviewAction.message[0].text = messageText;
+        updatedReportPreviewAction.message[0].html = shouldDeleteIOUReport ? '' : messageText;
+    }
+
+    if (updatedReportPreviewAction && reportPreviewAction?.childMoneyRequestCount && reportPreviewAction?.childMoneyRequestCount > 0) {
         updatedReportPreviewAction.childMoneyRequestCount = reportPreviewAction.childMoneyRequestCount - 1;
     }
 
     // STEP 5: Build Onyx data
-    const optimisticData = [
+    const optimisticData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
             value: null,
         },
-        ...(Permissions.canUseViolations(betas)
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.SET,
-                      key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
-                      value: null,
-                  },
-              ]
-            : []),
-        ...(shouldDeleteTransactionThread
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.SET,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`,
-                      value: null,
-                  },
-                  {
-                      onyxMethod: Onyx.METHOD.SET,
-                      key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`,
-                      value: null,
-                  },
-              ]
-            : []),
+    ];
+
+    if (Permissions.canUseViolations(betas)) {
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.SET,
+            key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
+            value: null,
+        });
+    }
+
+    if (shouldDeleteTransactionThread) {
+        optimisticData.push(
+            {
+                onyxMethod: Onyx.METHOD.SET,
+                key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`,
+                value: null,
+            },
+            {
+                onyxMethod: Onyx.METHOD.SET,
+                key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`,
+                value: null,
+            },
+        );
+    }
+
+    optimisticData.push(
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
             value: updatedReportAction,
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
             value: updatedIOUReport,
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
             value: {
-                [reportPreviewAction.reportActionID]: updatedReportPreviewAction,
+                [reportPreviewAction?.reportActionID ?? '']: updatedReportPreviewAction,
             },
         },
-        ...(!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
-                      value: {
-                          hasOutstandingChildRequest: false,
-                      },
-                  },
-              ]
-            : []),
-        ...(shouldDeleteIOUReport
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
-                      value: {
-                          hasOutstandingChildRequest: false,
-                          iouReportID: null,
-                          lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport.chatReportID, {[reportPreviewAction.reportActionID]: null}).lastMessageText,
-                          lastVisibleActionCreated: lodashGet(ReportActionsUtils.getLastVisibleAction(iouReport.chatReportID, {[reportPreviewAction.reportActionID]: null}), 'created'),
-                      },
-                  },
-              ]
-            : []),
-    ];
+    );
 
-    const successData = [
+    if (!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0) {
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
+            value: {
+                hasOutstandingChildRequest: false,
+            },
+        });
+    }
+
+    if (shouldDeleteIOUReport) {
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
+            value: {
+                hasOutstandingChildRequest: false,
+                iouReportID: null,
+                lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null})?.lastMessageText,
+                lastVisibleActionCreated: ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '', {[reportPreviewAction?.reportActionID ?? '']: null})?.created,
+            },
+        });
+    }
+
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
             value: {
                 [reportAction.reportActionID]: shouldDeleteIOUReport
                     ? null
@@ -2779,9 +2735,9 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView
         },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
             value: {
-                [reportPreviewAction.reportActionID]: shouldDeleteIOUReport
+                [reportPreviewAction?.reportActionID ?? '']: shouldDeleteIOUReport
                     ? null
                     : {
                           pendingAction: null,
@@ -2789,44 +2745,44 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView
                       },
             },
         },
-        ...(shouldDeleteIOUReport
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.SET,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
-                      value: null,
-                  },
-              ]
-            : []),
     ];
 
-    const failureData = [
+    if (shouldDeleteIOUReport) {
+        successData.push({
+            onyxMethod: Onyx.METHOD.SET,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
+            value: null,
+        });
+    }
+
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
             value: transaction,
         },
-        ...(Permissions.canUseViolations(betas)
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.SET,
-                      key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
-                      value: transactionViolations,
-                  },
-              ]
-            : []),
-        ...(shouldDeleteTransactionThread
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.SET,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`,
-                      value: transactionThread,
-                  },
-              ]
-            : []),
+    ];
+
+    if (Permissions.canUseViolations(betas)) {
+        failureData.push({
+            onyxMethod: Onyx.METHOD.SET,
+            key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
+            value: transactionViolations,
+        });
+    }
+
+    if (shouldDeleteTransactionThread) {
+        failureData.push({
+            onyxMethod: Onyx.METHOD.SET,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`,
+            value: transactionThread,
+        });
+    }
+
+    failureData.push(
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
             value: {
                 [reportAction.reportActionID]: {
                     ...reportAction,
@@ -2835,78 +2791,82 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView
                 },
             },
         },
-        {
-            onyxMethod: shouldDeleteIOUReport ? Onyx.METHOD.SET : Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
-            value: iouReport,
-        },
+        shouldDeleteIOUReport
+            ? {
+                  onyxMethod: Onyx.METHOD.SET,
+                  key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
+                  value: iouReport,
+              }
+            : {
+                  onyxMethod: Onyx.METHOD.MERGE,
+                  key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
+                  value: iouReport,
+              },
         {
             onyxMethod: Onyx.METHOD.MERGE,
-            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`,
+            key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
             value: {
-                [reportPreviewAction.reportActionID]: {
+                [reportPreviewAction?.reportActionID ?? '']: {
                     ...reportPreviewAction,
                     errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericDeleteFailureMessage'),
                 },
             },
         },
-        ...(shouldDeleteIOUReport
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
-                      value: chatReport,
-                  },
-              ]
-            : []),
-        ...(!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
-                      value: {
-                          hasOutstandingChildRequest: true,
-                      },
-                  },
-              ]
-            : []),
-    ];
+    );
+
+    if (chatReport && shouldDeleteIOUReport) {
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
+            value: chatReport,
+        });
+    }
+
+    if (!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0) {
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
+            value: {
+                hasOutstandingChildRequest: true,
+            },
+        });
+    }
+
+    const parameters: DeleteMoneyRequestParams = {
+        transactionID,
+        reportActionID: reportAction.reportActionID,
+    };
 
     // STEP 6: Make the API request
-    API.write(
-        'DeleteMoneyRequest',
-        {
-            transactionID,
-            reportActionID: reportAction.reportActionID,
-        },
-        {optimisticData, successData, failureData},
-    );
+    API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData});
 
     // STEP 7: Navigate the user depending on which page they are on and which resources were deleted
-    if (isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) {
+    if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) {
         // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report.
         Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID));
         return;
     }
 
-    if (shouldDeleteIOUReport) {
+    if (iouReport?.chatReportID && shouldDeleteIOUReport) {
         // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report.
         Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID));
     }
 }
 
 /**
- * @param {Object} report
- * @param {Number} amount
- * @param {String} currency
- * @param {String} comment
- * @param {String} paymentMethodType
- * @param {String} managerID - Account ID of the person sending the money
- * @param {Object} recipient - The user receiving the money
- * @returns {Object}
- */
-function getSendMoneyParams(report, amount, currency, comment, paymentMethodType, managerID, recipient) {
-    const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login);
+ * @param managerID - Account ID of the person sending the money
+ * @param recipient - The user receiving the money
+ */
+function getSendMoneyParams(
+    report: OnyxTypes.Report,
+    amount: number,
+    currency: string,
+    comment: string,
+    paymentMethodType: PaymentMethodType,
+    managerID: number,
+    recipient: Participant,
+): SendMoneyParamsData {
+    const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login ?? '');
     const recipientAccountID = Number(recipient.accountID);
     const newIOUReportDetails = JSON.stringify({
         amount,
@@ -2929,7 +2889,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
     const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientAccountID, managerID, amount, chatReport.reportID, currency, true);
 
     const optimisticTransaction = TransactionUtils.buildOptimisticTransaction(amount, currency, optimisticIOUReport.reportID, comment);
-    const optimisticTransactionData = {
+    const optimisticTransactionData: OnyxUpdate = {
         onyxMethod: Onyx.METHOD.SET,
         key: `${ONYXKEYS.COLLECTION.TRANSACTION}${optimisticTransaction.transactionID}`,
         value: optimisticTransaction,
@@ -2952,36 +2912,49 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
 
     const reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, optimisticIOUReport);
 
-    // First, add data that will be used in all cases
-    const optimisticChatReportData = {
-        onyxMethod: Onyx.METHOD.MERGE,
-        key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
-        value: {
-            ...chatReport,
-            lastReadTime: DateUtils.getDBTime(),
-            lastVisibleActionCreated: reportPreviewAction.created,
-        },
-    };
-    const optimisticIOUReportData = {
+    // Change the method to set for new reports because it doesn't exist yet, is faster,
+    // and we need the data to be available when we navigate to the chat page
+    const optimisticChatReportData: OnyxUpdate = isNewChat
+        ? {
+              onyxMethod: Onyx.METHOD.SET,
+              key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
+              value: {
+                  ...chatReport,
+                  // Set and clear pending fields on the chat report
+                  pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD},
+                  lastReadTime: DateUtils.getDBTime(),
+                  lastVisibleActionCreated: reportPreviewAction.created,
+              },
+          }
+        : {
+              onyxMethod: Onyx.METHOD.MERGE,
+              key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
+              value: {
+                  ...chatReport,
+                  lastReadTime: DateUtils.getDBTime(),
+                  lastVisibleActionCreated: reportPreviewAction.created,
+              },
+          };
+    const optimisticIOUReportData: OnyxUpdate = {
         onyxMethod: Onyx.METHOD.SET,
         key: `${ONYXKEYS.COLLECTION.REPORT}${optimisticIOUReport.reportID}`,
         value: {
             ...optimisticIOUReport,
-            lastMessageText: optimisticIOUReportAction.message[0].text,
-            lastMessageHtml: optimisticIOUReportAction.message[0].html,
+            lastMessageText: optimisticIOUReportAction.message?.[0].text,
+            lastMessageHtml: optimisticIOUReportAction.message?.[0].html,
         },
     };
-    const optimisticIOUReportActionsData = {
+    const optimisticIOUReportActionsData: OnyxUpdate = {
         onyxMethod: Onyx.METHOD.MERGE,
         key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticIOUReport.reportID}`,
         value: {
             [optimisticIOUReportAction.reportActionID]: {
-                ...optimisticIOUReportAction,
+                ...(optimisticIOUReportAction as OnyxTypes.ReportAction),
                 pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
             },
         },
     };
-    const optimisticChatReportActionsData = {
+    const optimisticChatReportActionsData: OnyxUpdate = {
         onyxMethod: Onyx.METHOD.MERGE,
         key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`,
         value: {
@@ -2989,7 +2962,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
         },
     };
 
-    const successData = [
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticIOUReport.reportID}`,
@@ -3015,7 +2988,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
         },
     ];
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${optimisticTransaction.transactionID}`,
@@ -3025,26 +2998,19 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
         },
     ];
 
-    let optimisticPersonalDetailListData = {};
+    let optimisticPersonalDetailListData: OnyxUpdate | EmptyObject = {};
 
     // Now, let's add the data we need just when we are creating a new chat report
     if (isNewChat) {
-        // Change the method to set for new reports because it doesn't exist yet, is faster,
-        // and we need the data to be available when we navigate to the chat page
-        optimisticChatReportData.onyxMethod = Onyx.METHOD.SET;
-        optimisticIOUReportData.onyxMethod = Onyx.METHOD.SET;
-
-        // Set and clear pending fields on the chat report
-        optimisticChatReportData.value.pendingFields = {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD};
         successData.push({
             onyxMethod: Onyx.METHOD.MERGE,
-            key: optimisticChatReportData.key,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
             value: {pendingFields: null},
         });
         failureData.push(
             {
                 onyxMethod: Onyx.METHOD.MERGE,
-                key: optimisticChatReportData.key,
+                key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
                 value: {
                     errorFields: {
                         createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'),
@@ -3070,14 +3036,18 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
                 [recipientAccountID]: {
                     accountID: recipientAccountID,
                     avatar: UserUtils.getDefaultAvatarURL(recipient.accountID),
+                    // Disabling this line since participant.displayName can be an empty string
+                    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
                     displayName: recipient.displayName || recipient.login,
                     login: recipient.login,
                 },
             },
         };
 
-        // Add an optimistic created action to the optimistic chat reportActions data
-        optimisticChatReportActionsData.value[optimisticCreatedAction.reportActionID] = optimisticCreatedAction;
+        if (optimisticChatReportActionsData.value) {
+            // Add an optimistic created action to the optimistic chat reportActions data
+            optimisticChatReportActionsData.value[optimisticCreatedAction.reportActionID] = optimisticCreatedAction;
+        }
     } else {
         failureData.push({
             onyxMethod: Onyx.METHOD.MERGE,
@@ -3090,8 +3060,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
         });
     }
 
-    const optimisticData = [optimisticChatReportData, optimisticIOUReportData, optimisticChatReportActionsData, optimisticIOUReportActionsData, optimisticTransactionData];
-    if (!_.isEmpty(optimisticPersonalDetailListData)) {
+    const optimisticData: OnyxUpdate[] = [optimisticChatReportData, optimisticIOUReportData, optimisticChatReportActionsData, optimisticIOUReportActionsData, optimisticTransactionData];
+    if (!isEmptyObject(optimisticPersonalDetailListData)) {
         optimisticData.push(optimisticPersonalDetailListData);
     }
 
@@ -3103,7 +3073,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
             paymentMethodType,
             transactionID: optimisticTransaction.transactionID,
             newIOUReportDetails,
-            createdReportActionID: isNewChat ? optimisticCreatedAction.reportActionID : 0,
+            createdReportActionID: isNewChat ? optimisticCreatedAction.reportActionID : '',
             reportPreviewReportActionID: reportPreviewAction.reportActionID,
         },
         optimisticData,
@@ -3112,18 +3082,11 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
     };
 }
 
-/**
- * @param {Object} chatReport
- * @param {Object} iouReport
- * @param {Object} recipient
- * @param {String} paymentMethodType
- * @returns {Object}
- */
-function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType) {
+function getPayMoneyRequestParams(chatReport: OnyxTypes.Report, iouReport: OnyxTypes.Report, recipient: Participant, paymentMethodType: PaymentMethodType): PayMoneyRequestData {
     const optimisticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction(
         CONST.IOU.REPORT_ACTION_TYPE.PAY,
-        -iouReport.total,
-        iouReport.currency,
+        -(iouReport.total ?? 0),
+        iouReport.currency ?? '',
         '',
         [recipient],
         '',
@@ -3140,9 +3103,9 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho
         optimisticReportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, true);
     }
 
-    const currentNextStep = lodashGet(allNextSteps, `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`, null);
+    const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`] ?? null;
 
-    const optimisticData = [
+    const optimisticData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`,
@@ -3152,8 +3115,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho
                 lastVisibleActionCreated: optimisticIOUReportAction.created,
                 hasOutstandingChildRequest: false,
                 iouReportID: null,
-                lastMessageText: optimisticIOUReportAction.message[0].text,
-                lastMessageHtml: optimisticIOUReportAction.message[0].html,
+                lastMessageText: optimisticIOUReportAction.message?.[0].text,
+                lastMessageHtml: optimisticIOUReportAction.message?.[0].html,
             },
         },
         {
@@ -3161,7 +3124,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
             value: {
                 [optimisticIOUReportAction.reportActionID]: {
-                    ...optimisticIOUReportAction,
+                    ...(optimisticIOUReportAction as OnyxTypes.ReportAction),
                     pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
                 },
             },
@@ -3171,8 +3134,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho
             key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
             value: {
                 ...iouReport,
-                lastMessageText: optimisticIOUReportAction.message[0].text,
-                lastMessageHtml: optimisticIOUReportAction.message[0].html,
+                lastMessageText: optimisticIOUReportAction.message?.[0].text,
+                lastMessageHtml: optimisticIOUReportAction.message?.[0].html,
                 hasOutstandingChildRequest: false,
                 statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED,
             },
@@ -3180,11 +3143,11 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: ONYXKEYS.NVP_LAST_PAYMENT_METHOD,
-            value: {[iouReport.policyID]: paymentMethodType},
+            value: {[iouReport.policyID ?? '']: paymentMethodType},
         },
     ];
 
-    const successData = [
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
@@ -3196,7 +3159,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho
         },
     ];
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
@@ -3218,7 +3181,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho
         },
     ];
 
-    if (!_.isNull(currentNextStep)) {
+    if (currentNextStep) {
         optimisticData.push({
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`,
@@ -3265,17 +3228,13 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho
 }
 
 /**
- * @param {Object} report
- * @param {Number} amount
- * @param {String} currency
- * @param {String} comment
- * @param {String} managerID - Account ID of the person sending the money
- * @param {Object} recipient - The user receiving the money
+ * @param managerID - Account ID of the person sending the money
+ * @param recipient - The user receiving the money
  */
-function sendMoneyElsewhere(report, amount, currency, comment, managerID, recipient) {
+function sendMoneyElsewhere(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) {
     const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, managerID, recipient);
 
-    API.write('SendMoneyElsewhere', params, {optimisticData, successData, failureData});
+    API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData});
 
     resetMoneyRequestInfo();
     Navigation.dismissModal(params.chatReportID);
@@ -3283,52 +3242,48 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerID, recipi
 }
 
 /**
- * @param {Object} report
- * @param {Number} amount
- * @param {String} currency
- * @param {String} comment
- * @param {String} managerID - Account ID of the person sending the money
- * @param {Object} recipient - The user receiving the money
+ * @param managerID - Account ID of the person sending the money
+ * @param recipient - The user receiving the money
  */
-function sendMoneyWithWallet(report, amount, currency, comment, managerID, recipient) {
+function sendMoneyWithWallet(report: OnyxTypes.Report, amount: number, currency: string, comment: string, managerID: number, recipient: Participant) {
     const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.EXPENSIFY, managerID, recipient);
 
-    API.write('SendMoneyWithWallet', params, {optimisticData, successData, failureData});
+    API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData});
 
     resetMoneyRequestInfo();
     Navigation.dismissModal(params.chatReportID);
     Report.notifyNewAction(params.chatReportID, managerID);
 }
 
-function approveMoneyRequest(expenseReport) {
-    const currentNextStep = lodashGet(allNextSteps, `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, null);
+function approveMoneyRequest(expenseReport: OnyxTypes.Report) {
+    const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`] ?? null;
 
-    const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(expenseReport.total, expenseReport.currency, expenseReport.reportID);
+    const optimisticApprovedReportAction = ReportUtils.buildOptimisticApprovedReportAction(expenseReport.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID);
 
-    const optimisticReportActionsData = {
+    const optimisticReportActionsData: OnyxUpdate = {
         onyxMethod: Onyx.METHOD.MERGE,
         key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
         value: {
             [optimisticApprovedReportAction.reportActionID]: {
-                ...optimisticApprovedReportAction,
+                ...(optimisticApprovedReportAction as OnyxTypes.ReportAction),
                 pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
             },
         },
     };
-    const optimisticIOUReportData = {
+    const optimisticIOUReportData: OnyxUpdate = {
         onyxMethod: Onyx.METHOD.MERGE,
         key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`,
         value: {
             ...expenseReport,
-            lastMessageText: optimisticApprovedReportAction.message[0].text,
-            lastMessageHtml: optimisticApprovedReportAction.message[0].html,
+            lastMessageText: optimisticApprovedReportAction.message?.[0].text,
+            lastMessageHtml: optimisticApprovedReportAction.message?.[0].html,
             stateNum: CONST.REPORT.STATE_NUM.APPROVED,
             statusNum: CONST.REPORT.STATUS_NUM.APPROVED,
         },
     };
-    const optimisticData = [optimisticIOUReportData, optimisticReportActionsData];
+    const optimisticData: OnyxUpdate[] = [optimisticIOUReportData, optimisticReportActionsData];
 
-    const successData = [
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
@@ -3340,19 +3295,19 @@ function approveMoneyRequest(expenseReport) {
         },
     ];
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
             value: {
-                [expenseReport.reportActionID]: {
+                [expenseReport.reportActionID ?? '']: {
                     errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'),
                 },
             },
         },
     ];
 
-    if (!_.isNull(currentNextStep)) {
+    if (currentNextStep) {
         optimisticData.push({
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`,
@@ -3365,27 +3320,29 @@ function approveMoneyRequest(expenseReport) {
         });
     }
 
-    API.write('ApproveMoneyRequest', {reportID: expenseReport.reportID, approvedReportActionID: optimisticApprovedReportAction.reportActionID}, {optimisticData, successData, failureData});
+    const parameters: ApproveMoneyRequestParams = {
+        reportID: expenseReport.reportID,
+        approvedReportActionID: optimisticApprovedReportAction.reportActionID,
+    };
+
+    API.write(WRITE_COMMANDS.APPROVE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData});
 }
 
-/**
- * @param {Object} expenseReport
- */
-function submitReport(expenseReport) {
-    const currentNextStep = lodashGet(allNextSteps, `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`, null);
+function submitReport(expenseReport: OnyxTypes.Report) {
+    const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`] ?? null;
 
-    const optimisticSubmittedReportAction = ReportUtils.buildOptimisticSubmittedReportAction(expenseReport.total, expenseReport.currency, expenseReport.reportID);
+    const optimisticSubmittedReportAction = ReportUtils.buildOptimisticSubmittedReportAction(expenseReport?.total ?? 0, expenseReport.currency ?? '', expenseReport.reportID);
     const parentReport = ReportUtils.getReport(expenseReport.parentReportID);
     const policy = ReportUtils.getPolicy(expenseReport.policyID);
     const isCurrentUserManager = currentUserPersonalDetails.accountID === expenseReport.managerID;
 
-    const optimisticData = [
+    const optimisticData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
             value: {
                 [optimisticSubmittedReportAction.reportActionID]: {
-                    ...optimisticSubmittedReportAction,
+                    ...(optimisticSubmittedReportAction as OnyxTypes.ReportAction),
                     pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
                 },
             },
@@ -3395,30 +3352,28 @@ function submitReport(expenseReport) {
             key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`,
             value: {
                 ...expenseReport,
-                lastMessageText: lodashGet(optimisticSubmittedReportAction, 'message.0.text', ''),
-                lastMessageHtml: lodashGet(optimisticSubmittedReportAction, 'message.0.html', ''),
+                lastMessageText: optimisticSubmittedReportAction.message?.[0].text ?? '',
+                lastMessageHtml: optimisticSubmittedReportAction.message?.[0].html ?? '',
                 stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
                 statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
             },
         },
-        ...(parentReport.reportID
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`,
-                      value: {
-                          ...parentReport,
-
-                          // In case its a manager who force submitted the report, they are the next user who needs to take an action
-                          hasOutstandingChildRequest: isCurrentUserManager,
-                          iouReportID: null,
-                      },
-                  },
-              ]
-            : []),
     ];
 
-    const successData = [
+    if (parentReport?.reportID) {
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`,
+            value: {
+                ...parentReport,
+                // In case its a manager who force submitted the report, they are the next user who needs to take an action
+                hasOutstandingChildRequest: isCurrentUserManager,
+                iouReportID: null,
+            },
+        });
+    }
+
+    const successData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
@@ -3430,7 +3385,7 @@ function submitReport(expenseReport) {
         },
     ];
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
@@ -3448,21 +3403,20 @@ function submitReport(expenseReport) {
                 stateNum: CONST.REPORT.STATE_NUM.OPEN,
             },
         },
-        ...(parentReport.reportID
-            ? [
-                  {
-                      onyxMethod: Onyx.METHOD.MERGE,
-                      key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`,
-                      value: {
-                          hasOutstandingChildRequest: parentReport.hasOutstandingChildRequest,
-                          iouReportID: expenseReport.reportID,
-                      },
-                  },
-              ]
-            : []),
     ];
 
-    if (!_.isNull(currentNextStep)) {
+    if (parentReport?.reportID) {
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${parentReport.reportID}`,
+            value: {
+                hasOutstandingChildRequest: parentReport.hasOutstandingChildRequest,
+                iouReportID: expenseReport.reportID,
+            },
+        });
+    }
+
+    if (currentNextStep) {
         optimisticData.push({
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${expenseReport.reportID}`,
@@ -3475,40 +3429,32 @@ function submitReport(expenseReport) {
         });
     }
 
-    API.write(
-        'SubmitReport',
-        {
-            reportID: expenseReport.reportID,
-            managerAccountID: policy.submitsTo || expenseReport.managerID,
-            reportActionID: optimisticSubmittedReportAction.reportActionID,
-        },
-        {optimisticData, successData, failureData},
-    );
+    const parameters: SubmitReportParams = {
+        reportID: expenseReport.reportID,
+        managerAccountID: policy.submitsTo ?? expenseReport.managerID,
+        reportActionID: optimisticSubmittedReportAction.reportActionID,
+    };
+
+    API.write(WRITE_COMMANDS.SUBMIT_REPORT, parameters, {optimisticData, successData, failureData});
 }
 
-/**
- * @param {String} paymentType
- * @param {Object} chatReport
- * @param {Object} iouReport
- * @param {String} reimbursementBankAccountState
- */
-function payMoneyRequest(paymentType, chatReport, iouReport) {
+function payMoneyRequest(paymentType: PaymentMethodType, chatReport: OnyxTypes.Report, iouReport: OnyxTypes.Report) {
     const recipient = {accountID: iouReport.ownerAccountID};
     const {params, optimisticData, successData, failureData} = getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentType);
 
     // For now we need to call the PayMoneyRequestWithWallet API since PayMoneyRequest was not updated to work with
     // Expensify Wallets.
-    const apiCommand = paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY ? 'PayMoneyRequestWithWallet' : 'PayMoneyRequest';
+    const apiCommand = paymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY ? WRITE_COMMANDS.PAY_MONEY_REQUEST_WITH_WALLET : WRITE_COMMANDS.PAY_MONEY_REQUEST;
 
     API.write(apiCommand, params, {optimisticData, successData, failureData});
     Navigation.dismissModalWithReport(chatReport);
 }
 
-function detachReceipt(transactionID) {
-    const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] || {};
-    const newTransaction = {...transaction, filename: '', receipt: {}};
+function detachReceipt(transactionID: string) {
+    const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
+    const newTransaction = transaction ? {...transaction, filename: '', receipt: {}} : null;
 
-    const optimisticData = [
+    const optimisticData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.SET,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
@@ -3516,7 +3462,7 @@ function detachReceipt(transactionID) {
         },
     ];
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
@@ -3524,22 +3470,20 @@ function detachReceipt(transactionID) {
         },
     ];
 
-    API.write('DetachReceipt', {transactionID}, {optimisticData, failureData});
+    const parameters: DetachReceiptParams = {transactionID};
+
+    API.write(WRITE_COMMANDS.DETACH_RECEIPT, parameters, {optimisticData, failureData});
 }
 
-/**
- * @param {String} transactionID
- * @param {Object} file
- * @param {String} source
- */
-function replaceReceipt(transactionID, file, source) {
-    const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] || {};
-    const oldReceipt = lodashGet(transaction, 'receipt', {});
+function replaceReceipt(transactionID: string, file: File, source: string) {
+    const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
+    const oldReceipt = transaction?.receipt ?? {};
     const receiptOptimistic = {
         source,
         state: CONST.IOU.RECEIPT_STATE.OPEN,
     };
-    const optimisticData = [
+
+    const optimisticData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
@@ -3550,95 +3494,73 @@ function replaceReceipt(transactionID, file, source) {
         },
     ];
 
-    const failureData = [
+    const failureData: OnyxUpdate[] = [
         {
             onyxMethod: Onyx.METHOD.MERGE,
             key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
             value: {
                 receipt: oldReceipt,
-                filename: transaction.filename,
+                filename: transaction?.filename,
                 errors: getReceiptError(receiptOptimistic, file.name),
             },
         },
     ];
 
-    API.write('ReplaceReceipt', {transactionID, receipt: file}, {optimisticData, failureData});
+    const parameters: ReplaceReceiptParams = {
+        transactionID,
+        receipt: file,
+    };
+
+    API.write(WRITE_COMMANDS.REPLACE_RECEIPT, parameters, {optimisticData, failureData});
 }
 
 /**
  * Finds the participants for an IOU based on the attached report
- * @param {String} transactionID of the transaction to set the participants of
- * @param {Object} report attached to the transaction
+ * @param transactionID of the transaction to set the participants of
+ * @param report attached to the transaction
  */
-function setMoneyRequestParticipantsFromReport(transactionID, report) {
+function setMoneyRequestParticipantsFromReport(transactionID: string, report: OnyxTypes.Report) {
     // If the report is iou or expense report, we should get the chat report to set participant for request money
     const chatReport = ReportUtils.isMoneyRequestReport(report) ? ReportUtils.getReport(report.chatReportID) : report;
     const currentUserAccountID = currentUserPersonalDetails.accountID;
-    const participants = ReportUtils.isPolicyExpenseChat(chatReport)
-        ? [{reportID: chatReport.reportID, isPolicyExpenseChat: true, selected: true}]
-        : _.chain(chatReport.participantAccountIDs)
-              .filter((accountID) => currentUserAccountID !== accountID)
-              .map((accountID) => ({accountID, selected: true}))
-              .value();
+    const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport)
+        ? [{reportID: chatReport?.reportID, isPolicyExpenseChat: true, selected: true}]
+        : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true}));
+
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {participants, participantsAutoAssigned: true});
 }
 
-/**
- * Initialize money request info and navigate to the MoneyRequest page
- * @param {String} iouType
- * @param {String} reportID
- */
-function startMoneyRequest(iouType, reportID = '') {
+/** Initialize money request info and navigate to the MoneyRequest page */
+function startMoneyRequest(iouType: string, reportID = '') {
     resetMoneyRequestInfo(`${iouType}${reportID}`);
     Navigation.navigate(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID));
 }
 
-/**
- * @param {String} id
- */
-function setMoneyRequestId(id) {
+function setMoneyRequestId(id: string) {
     Onyx.merge(ONYXKEYS.IOU, {id});
 }
 
-/**
- * @param {Number} amount
- */
-function setMoneyRequestAmount(amount) {
+function setMoneyRequestAmount(amount: number) {
     Onyx.merge(ONYXKEYS.IOU, {amount});
 }
 
-/**
- * @param {String} created
- */
-function setMoneyRequestCreated(created) {
+function setMoneyRequestCreated(created: string) {
     Onyx.merge(ONYXKEYS.IOU, {created});
 }
 
-/**
- * @param {String} currency
- */
-function setMoneyRequestCurrency(currency) {
+function setMoneyRequestCurrency(currency: string) {
     Onyx.merge(ONYXKEYS.IOU, {currency});
 }
 
-/**
- * @param {String} comment
- */
-function setMoneyRequestDescription(comment) {
+function setMoneyRequestDescription(comment: string) {
     Onyx.merge(ONYXKEYS.IOU, {comment: comment.trim()});
 }
 
-/**
- * @param {String} merchant
- */
-function setMoneyRequestMerchant(merchant) {
+function setMoneyRequestMerchant(merchant: string) {
     Onyx.merge(ONYXKEYS.IOU, {merchant: merchant.trim()});
 }
 
-/**
- * @param {String} category
- */
-function setMoneyRequestCategory(category) {
+function setMoneyRequestCategory(category: string) {
     Onyx.merge(ONYXKEYS.IOU, {category});
 }
 
@@ -3646,34 +3568,19 @@ function resetMoneyRequestCategory() {
     Onyx.merge(ONYXKEYS.IOU, {category: ''});
 }
 
-/**
- * @param {String} transactionID
- * @param {Object} taxRate
- */
-function setMoneyRequestTaxRate(transactionID, taxRate) {
+function setMoneyRequestTaxRate(transactionID: string, taxRate: TaxRate) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {taxRate});
 }
 
-/**
- * @param {String} transactionID
- * @param {Number} taxAmount
- */
-function setMoneyRequestTaxAmount(transactionID, taxAmount) {
+function setMoneyRequestTaxAmount(transactionID: string, taxAmount: number) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {taxAmount});
 }
 
-/**
- * @param {Boolean} billable
- */
-function setMoneyRequestBillable(billable) {
+function setMoneyRequestBillable(billable: boolean) {
     Onyx.merge(ONYXKEYS.IOU, {billable});
 }
 
-/**
- * @param {Object[]} participants
- * @param {Boolean} isSplitRequest
- */
-function setMoneyRequestParticipants(participants, isSplitRequest) {
+function setMoneyRequestParticipants(participants: Participant[], isSplitRequest?: boolean) {
     Onyx.merge(ONYXKEYS.IOU, {participants, isSplitRequest});
 }
 
@@ -3686,18 +3593,10 @@ function setUpDistanceTransaction() {
     Onyx.merge(ONYXKEYS.IOU, {transactionID});
 }
 
-/**
- * Navigates to the next IOU page based on where the IOU request was started
- *
- * @param {Object} iou
- * @param {String} iouType
- * @param {Object} report
- * @param {String} report.reportID
- * @param {String} path
- */
-function navigateToNextPage(iou, iouType, report, path = '') {
-    const moneyRequestID = `${iouType}${report.reportID || ''}`;
-    const shouldReset = iou.id !== moneyRequestID && !_.isEmpty(report.reportID);
+/** Navigates to the next IOU page based on where the IOU request was started */
+function navigateToNextPage(iou: OnyxEntry<OnyxTypes.IOU>, iouType: string, report?: OnyxTypes.Report, path = '') {
+    const moneyRequestID = `${iouType}${report?.reportID ?? ''}`;
+    const shouldReset = iou?.id !== moneyRequestID && !!report?.reportID;
 
     // If the money request ID in Onyx does not match the ID from params, we want to start a new request
     // with the ID from params. We need to clear the participants in case the new request is initiated from FAB.
@@ -3706,24 +3605,21 @@ function navigateToNextPage(iou, iouType, report, path = '') {
     }
 
     // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it.
-    if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report.reportID)) {
-        Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID));
+    if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) {
+        Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report?.reportID));
         return;
     }
 
     // If a request is initiated on a report, skip the participants selection step and navigate to the confirmation page.
-    if (report.reportID) {
+    if (report?.reportID) {
         // If the report is iou or expense report, we should get the chat report to set participant for request money
         const chatReport = ReportUtils.isMoneyRequestReport(report) ? ReportUtils.getReport(report.chatReportID) : report;
         // Reinitialize the participants when the money request ID in Onyx does not match the ID from params
-        if (_.isEmpty(iou.participants) || shouldReset) {
+        if (!iou?.participants?.length || shouldReset) {
             const currentUserAccountID = currentUserPersonalDetails.accountID;
-            const participants = ReportUtils.isPolicyExpenseChat(chatReport)
-                ? [{reportID: chatReport.reportID, isPolicyExpenseChat: true, selected: true}]
-                : _.chain(chatReport.participantAccountIDs)
-                      .filter((accountID) => currentUserAccountID !== accountID)
-                      .map((accountID) => ({accountID, selected: true}))
-                      .value();
+            const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport)
+                ? [{reportID: chatReport?.reportID, isPolicyExpenseChat: true, selected: true}]
+                : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true}));
             setMoneyRequestParticipants(participants);
             resetMoneyRequestCategory();
         }
@@ -3737,28 +3633,23 @@ function navigateToNextPage(iou, iouType, report, path = '') {
  *  When the money request or split bill creation flow is initialized via FAB, the reportID is not passed as a navigation
  * parameter.
  * Gets a report id from the first participant of the IOU object stored in Onyx.
- * @param {Object} iou
- * @param {Array} iou.participants
- * @param {Object} route
- * @param {Object} route.params
- * @param {String} [route.params.reportID]
- * @returns {String}
  */
-function getIOUReportID(iou, route) {
-    return lodashGet(route, 'params.reportID') || lodashGet(iou, 'participants.0.reportID', '');
+function getIOUReportID(iou?: OnyxTypes.IOU, route?: MoneyRequestRoute): string {
+    // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null
+    // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+    return route?.params.reportID || iou?.participants?.[0]?.reportID || '';
 }
 
-/**
- * @param {String} receiptFilename
- * @param {String} receiptPath
- * @param {Function} onSuccess
- * @param {String} requestType
- * @param {String} iouType
- * @param {String} transactionID
- * @param {String} reportID
- */
 // eslint-disable-next-line rulesdir/no-negated-variables
-function navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath, onSuccess, requestType, iouType, transactionID, reportID) {
+function navigateToStartStepIfScanFileCannotBeRead(
+    receiptFilename: string,
+    receiptPath: string,
+    onSuccess: (file: File) => void,
+    requestType: ValueOf<typeof CONST.IOU.REQUEST_TYPE>,
+    iouType: ValueOf<typeof CONST.IOU.TYPE>,
+    transactionID: string,
+    reportID: string,
+) {
     if (!receiptFilename || !receiptPath) {
         return;
     }
@@ -3774,12 +3665,8 @@ function navigateToStartStepIfScanFileCannotBeRead(receiptFilename, receiptPath,
     FileUtils.readFileAsync(receiptPath, receiptFilename, onSuccess, onFailure);
 }
 
-/**
- * Save the preferred payment method for a policy
- * @param {String} policyID
- * @param {String} paymentMethod
- */
-function savePreferredPaymentMethod(policyID, paymentMethod) {
+/** Save the preferred payment method for a policy */
+function savePreferredPaymentMethod(policyID: string, paymentMethod: PaymentMethodType) {
     Onyx.merge(`${ONYXKEYS.NVP_LAST_PAYMENT_METHOD}`, {[policyID]: paymentMethod});
 }
 
diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts
index dc09f81af60b..bd93974d91c6 100644
--- a/src/libs/actions/Policy.ts
+++ b/src/libs/actions/Policy.ts
@@ -1518,7 +1518,7 @@ function dismissAddedWithPrimaryLoginMessages(policyID: string) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {primaryLoginsInvited: null});
 }
 
-function buildOptimisticPolicyRecentlyUsedCategories(policyID: string, category: string) {
+function buildOptimisticPolicyRecentlyUsedCategories(policyID?: string, category?: string) {
     if (!policyID || !category) {
         return [];
     }
@@ -1528,7 +1528,7 @@ function buildOptimisticPolicyRecentlyUsedCategories(policyID: string, category:
     return lodashUnion([category], policyRecentlyUsedCategories);
 }
 
-function buildOptimisticPolicyRecentlyUsedTags(policyID: string, tag: string): RecentlyUsedTags {
+function buildOptimisticPolicyRecentlyUsedTags(policyID?: string, tag?: string): RecentlyUsedTags {
     if (!policyID || !tag) {
         return {};
     }
diff --git a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx
index 997d9baa4f59..d5900330e4ba 100644
--- a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx
+++ b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx
@@ -22,7 +22,6 @@ import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 import type {LoginList} from '@src/types/onyx';
-import type {Errors} from '@src/types/onyx/OnyxCommon';
 
 type IntroSchoolPrincipalPageOnyxProps = {
     loginList: OnyxEntry<LoginList>;
@@ -48,7 +47,7 @@ function IntroSchoolPrincipalPage(props: IntroSchoolPrincipalPageProps) {
      */
     const validate = useCallback(
         (values: OnyxFormValuesFields<typeof ONYXKEYS.FORMS.INTRO_SCHOOL_PRINCIPAL_FORM>) => {
-            const errors: Errors = {};
+            const errors: Partial<Record<keyof OnyxFormValuesFields<typeof ONYXKEYS.FORMS.INTRO_SCHOOL_PRINCIPAL_FORM>, string>> = {};
 
             if (!values.firstName || !ValidationUtils.isValidPersonName(values.firstName)) {
                 ErrorUtils.addErrorMessage(errors, 'firstName', 'bankAccount.error.firstName');
diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx
index 272548214ece..9c8c6a8b37e7 100644
--- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx
+++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx
@@ -250,7 +250,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef<ReportA
         callbackWhenDeleteModalHide.current = () => (onComfirmDeleteModal.current = runAndResetCallback(onComfirmDeleteModal.current));
         const reportAction = reportActionRef.current;
         if (ReportActionsUtils.isMoneyRequestAction(reportAction) && reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU) {
-            IOU.deleteMoneyRequest(reportAction?.originalMessage?.IOUTransactionID, reportAction);
+            IOU.deleteMoneyRequest(reportAction?.originalMessage?.IOUTransactionID ?? '', reportAction);
         } else if (reportAction) {
             Report.deleteReportComment(reportIDRef.current, reportAction);
         }
diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts
index e4a195dc291e..b04011978d73 100644
--- a/src/types/onyx/IOU.ts
+++ b/src/types/onyx/IOU.ts
@@ -1,29 +1,49 @@
+import type {ValueOf} from 'type-fest';
+import type CONST from '@src/CONST';
 import type {Icon} from './OnyxCommon';
 
 type Participant = {
-    accountID: number;
-    login: string;
+    accountID?: number;
+    login?: string;
+    displayName?: string;
     isPolicyExpenseChat?: boolean;
     isOwnPolicyExpenseChat?: boolean;
-    selected?: boolean;
+    chatType?: ValueOf<typeof CONST.REPORT.CHAT_TYPE>;
     reportID?: string;
+    policyID?: string;
+    selected?: boolean;
     searchText?: string;
-    alternateText: string;
-    firstName: string;
-    icons: Icon[];
-    keyForList: string;
-    lastName: string;
-    phoneNumber: string;
-    text: string;
+    alternateText?: string;
+    firstName?: string;
+    icons?: Icon[];
+    keyForList?: string;
+    lastName?: string;
+    phoneNumber?: string;
+    text?: string;
     isSelected?: boolean;
 };
 
+type Split = {
+    email?: string;
+    amount?: number;
+    accountID?: number;
+    chatReportID?: string;
+    iouReportID?: string;
+    reportActionID?: string;
+    transactionID?: string;
+    policyID?: string;
+    createdChatReportActionID?: string;
+    createdIOUReportActionID?: string;
+    reportPreviewReportActionID?: string;
+};
+
 type IOU = {
     id: string;
     amount?: number;
     /** Selected Currency Code of the current IOU */
     currency?: string;
     comment?: string;
+    category?: string;
     merchant?: string;
     created?: string;
     receiptPath?: string;
@@ -31,7 +51,9 @@ type IOU = {
     transactionID?: string;
     participants?: Participant[];
     tag?: string;
+    billable?: boolean;
+    isSplitRequest?: boolean;
 };
 
 export default IOU;
-export type {Participant};
+export type {Participant, Split};
diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts
index 2dafe16b5388..2bb6eca8c3f0 100644
--- a/src/types/onyx/OnyxCommon.ts
+++ b/src/types/onyx/OnyxCommon.ts
@@ -8,7 +8,7 @@ type PendingFields<TKey extends string = string> = Record<TKey, PendingAction |
 
 type ErrorFields<TKey extends string = string> = Record<TKey, Errors | null | undefined>;
 
-type Errors = Record<string, string>;
+type Errors = Record<string, string | null>;
 
 type AvatarType = typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;
 
diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index e392cb23384a..fbd61a9c5365 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -88,6 +88,9 @@ type Report = {
     /** ID of the report */
     reportID: string;
 
+    /** ID of the report action */
+    reportActionID?: string;
+
     /** ID of the chat report */
     chatReportID?: string;
 
diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts
index d2f0afad5b7a..3ec98fd43178 100644
--- a/src/types/onyx/ReportAction.ts
+++ b/src/types/onyx/ReportAction.ts
@@ -143,6 +143,9 @@ type ReportActionBase = {
     /** Type of child report  */
     childType?: string;
 
+    /** The user's ID */
+    accountID?: number;
+
     childOldestFourEmails?: string;
     childOldestFourAccountIDs?: string;
     childCommenterCount?: number;
@@ -178,7 +181,7 @@ type ReportActionBase = {
     delegateAccountID?: number;
 
     /** Server side errors keyed by microtime */
-    errors?: OnyxCommon.Errors;
+    errors?: OnyxCommon.Errors | OnyxCommon.ErrorFields;
 
     /** Whether the report action is attachment */
     isAttachment?: boolean;
diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts
index fe7ca7436a81..b559346a48de 100644
--- a/src/types/onyx/Transaction.ts
+++ b/src/types/onyx/Transaction.ts
@@ -1,5 +1,6 @@
 import type {ValueOf} from 'type-fest';
 import type CONST from '@src/CONST';
+import type {Participant, Split} from './IOU';
 import type * as OnyxCommon from './OnyxCommon';
 import type RecentWaypoint from './RecentWaypoint';
 
@@ -18,6 +19,7 @@ type Waypoint = {
 };
 
 type WaypointCollection = Record<string, RecentWaypoint | Waypoint>;
+
 type Comment = {
     comment?: string;
     waypoints?: WaypointCollection;
@@ -26,6 +28,7 @@ type Comment = {
     customUnit?: Record<string, unknown>;
     source?: string;
     originalTransactionID?: string;
+    splits?: Split[];
 };
 
 type GeometryType = 'LineString';
@@ -35,10 +38,14 @@ type Geometry = {
     type?: GeometryType;
 };
 
+type ReceiptSource = string | number;
+
 type Receipt = {
     receiptID?: number;
     path?: string;
-    source?: string;
+    name?: string;
+    source?: ReceiptSource;
+    filename?: string;
     state?: ValueOf<typeof CONST.IOU.RECEIPT_STATE>;
 };
 
@@ -55,52 +62,150 @@ type ReceiptError = {error?: string; source: string; filename: string};
 
 type ReceiptErrors = Record<string, ReceiptError>;
 
+type TaxRateData = {
+    name: string;
+    value: string;
+    code?: string;
+};
+
+type TaxRate = {
+    text: string;
+    keyForList: string;
+    searchText: string;
+    tooltipText: string;
+    isDisabled?: boolean;
+    data?: TaxRateData;
+};
+
 type Transaction = {
+    /** The original transaction amount */
     amount: number;
-    billable: boolean;
-    category: string;
+
+    /** Whether the request is billable */
+    billable?: boolean;
+
+    /** The category name */
+    category?: string;
+
+    /** The comment object on the transaction */
     comment: Comment;
+
+    /** Date that the request was created */
     created: string;
+
+    /** The original currency of the transaction */
     currency: string;
+
+    /** Any additional error message to show */
     errors?: OnyxCommon.Errors | ReceiptErrors;
+
+    /** Server side errors keyed by microtime */
     errorFields?: OnyxCommon.ErrorFields<'route'>;
-    // The name of the file used for a receipt (formerly receiptFilename)
+
+    /** The name of the file used for a receipt (formerly receiptFilename) */
     filename?: string;
-    // Used during the creation flow before the transaction is saved to the server
+
+    /** Used during the creation flow before the transaction is saved to the server */
     iouRequestType?: ValueOf<typeof CONST.IOU.REQUEST_TYPE>;
+
+    /** The original merchant name */
     merchant: string;
+
+    /** The edited transaction amount */
     modifiedAmount?: number;
+
+    /** The edited transaction date */
     modifiedCreated?: string;
+
+    /** The edited currency of the transaction */
     modifiedCurrency?: string;
+
+    /** The edited merchant name */
     modifiedMerchant?: string;
+
+    /** The edited waypoints for the distance request */
     modifiedWaypoints?: WaypointCollection;
-    // Used during the creation flow before the transaction is saved to the server and helps dictate where the user is navigated to when pressing the back button on the confirmation step
+
+    /**
+     * Used during the creation flow before the transaction is saved to the server and helps dictate where
+     * the user is navigated to when pressing the back button on the confirmation step
+     */
     participantsAutoAssigned?: boolean;
-    pendingAction: OnyxCommon.PendingAction;
+
+    /** Selected participants */
+    participants?: Participant[];
+
+    /** The type of action that's pending  */
+    pendingAction?: OnyxCommon.PendingAction;
+
+    /** The receipt object associated with the transaction */
     receipt?: Receipt;
+
+    /** The iouReportID associated with the transaction */
     reportID: string;
+
+    /** Existing routes */
     routes?: Routes;
+
+    /** The transaction id */
     transactionID: string;
-    tag: string;
+
+    /** The transaction tag */
+    tag?: string;
+
+    /** Whether the transaction was created globally */
+    isFromGlobalCreate?: boolean;
+
+    /** The transaction tax rate */
+    taxRate?: TaxRate;
+
+    /** Tax amount */
+    taxAmount?: number;
+
+    /** Pending fields for the transaction */
     pendingFields?: Partial<{[K in TransactionPendingFieldsKey]: ValueOf<typeof CONST.RED_BRICK_ROAD_PENDING_ACTION>}>;
 
     /** Card Transactions */
 
+    /** The parent transaction id */
     parentTransactionID?: string;
+
+    /** Whether the expense is reimbursable or not */
     reimbursable?: boolean;
+
     /** The CC for this transaction */
     cardID?: number;
+
     /** If the transaction is pending or posted */
     status?: ValueOf<typeof CONST.TRANSACTION.STATUS>;
+
     /** If an EReceipt should be generated for this transaction */
     hasEReceipt?: boolean;
+
     /** The MCC Group for this transaction */
     mccGroup?: ValueOf<typeof CONST.MCC_GROUPS>;
+
+    /** Modified MCC Group */
     modifiedMCCGroup?: ValueOf<typeof CONST.MCC_GROUPS>;
+
     /** If the transaction was made in a foreign currency, we send the original amount and currency */
     originalAmount?: number;
+
+    /** The original currency of the transaction */
     originalCurrency?: string;
+
+    /** Indicates transaction loading */
+    isLoading?: boolean;
+};
+
+type AdditionalTransactionChanges = {
+    comment?: string;
+    waypoints?: WaypointCollection;
+    oldAmount?: number;
+    oldCurrency?: string;
 };
 
+type TransactionChanges = Partial<Transaction> & AdditionalTransactionChanges;
+
 export default Transaction;
-export type {WaypointCollection, Comment, Receipt, Waypoint, ReceiptError, ReceiptErrors, TransactionPendingFieldsKey};
+export type {WaypointCollection, Comment, Receipt, Waypoint, ReceiptError, ReceiptErrors, TransactionPendingFieldsKey, TransactionChanges, TaxRate, ReceiptSource};
