Skip to content

Fix TypeScript errors and lint violations in Expo Router migration#406

Merged
manuthecoder merged 4 commits intouse-expo-routerfrom
copilot/rewrite-navigation-to-expo-router
Mar 5, 2026
Merged

Fix TypeScript errors and lint violations in Expo Router migration#406
manuthecoder merged 4 commits intouse-expo-routerfrom
copilot/rewrite-navigation-to-expo-router

Conversation

Copy link

Copilot AI commented Mar 5, 2026

Summary of the problem

PR #399 migrated HCB Mobile from React Native Navigation to Expo Router, but left 29 TypeScript compilation errors and 20 ESLint errors that blocked merging. The root causes: Expo Router route params must be serializable primitives (not objects), useLocalSearchParams() returns string | string[] by default, and several navigation-related variables/imports became dead code post-migration.

Describe your changes

fallbackData serialization — Route params cannot carry complex objects across Expo Router navigations:

// Before (type error: unknown not assignable to UnknownInputParams)
params: { id: org.id, fallbackData: org as unknown }

// After
params: { id: org.id, fallbackData: JSON.stringify(org) }
// Receiving end:
fallbackData: params.fallbackData ? JSON.parse(params.fallbackData) : undefined

Typed useLocalSearchParams — All dynamic route files now use explicit generics to avoid string | string[] errors:

const params = useLocalSearchParams<{ id: string; fallbackData?: string }>();

Other TypeScript fixes:

  • SWRCacheProvider null context in _layout.tsx — non-null assertion (context is always provided by parent layout)
  • Navbar options prop typed as { title?: string } instead of unknown
  • selection.tsx transaction type extended with memo + optional chaining on possibly-null access
  • formatEntityNames signature accepts string | undefined | null from getName() to match actual Merchant/Category implementations
  • Removed now-unnecessary @ts-ignore in Transaction.tsx (underlying error was resolved upstream)

ESLint fixes (20 errors → 0):

  • Renamed unused navigation destructured params to navigation: _navigation in 10 transaction type components
  • Removed dead imports: getTransactionTitle, router, useSWRConfig
  • Fixed import ordering in TransferTransaction.tsx and util.ts
  • Prefixed unused eligibleOrganizations/navigation locals in order.tsx and transactions/index.tsx
  • Added eslint-disable for intentional conditional require() in useDigitalWallet.ts (iOS watch connectivity, must stay as try/catch require)

Checklist

  • Descriptive PR title (Does the title explain the changes in a concise manner?)
  • Tag related issues so they auto-close on merge
  • Easily digestible commits (Are the commits small and easy to understand?) video
  • CI passes (Do the GitHub checks pass?)
  • Tested by submitter before requesting review (Does it work in development iOS/android? )

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 3 commits March 5, 2026 01:54
Co-authored-by: manuthecoder <77016441+manuthecoder@users.noreply.github.com>
Co-authored-by: manuthecoder <77016441+manuthecoder@users.noreply.github.com>
Co-authored-by: manuthecoder <77016441+manuthecoder@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor hcb mobile to use expo router Fix TypeScript errors and lint violations in Expo Router migration Mar 5, 2026
@manuthecoder manuthecoder marked this pull request as ready for review March 5, 2026 02:13
@manuthecoder manuthecoder requested a review from a team as a code owner March 5, 2026 02:13
Copilot AI review requested due to automatic review settings March 5, 2026 02:13
@manuthecoder manuthecoder merged commit 9ffe533 into use-expo-router Mar 5, 2026
2 checks passed
@manuthecoder manuthecoder deleted the copilot/rewrite-navigation-to-expo-router branch March 5, 2026 02:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR finishes the Expo Router migration cleanup by resolving remaining TypeScript and ESLint violations, primarily around Expo Router param serialization/typing and unused navigation props introduced by the navigation rewrite.

Changes:

  • Serialize complex route params (e.g., organization fallback data) and add typed useLocalSearchParams generics in dynamic routes.
  • Remove/rename unused imports and variables to satisfy ESLint (navigation_navigation, import ordering, dead imports).
  • Small type fixes and safety tweaks (e.g., formatEntityNames signature, Transaction.tsx ts-expect cleanup, receipts selection memo typing).

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/utils/util.ts Updates helpers to support Expo Router param serialization and adjusts yellowpages name typing.
src/lib/yellowpages/data.json Updates bundled metadata timestamp in yellowpages dataset.
src/lib/yellowpages/.last-updated Updates dataset build timestamp marker.
src/lib/useDigitalWallet.ts Adds targeted ESLint suppression for intentional require() usage.
src/components/transaction/types/WiseTransaction.tsx Renames unused navigation prop to _navigation to satisfy lint.
src/components/transaction/types/TransferTransaction.tsx Fixes import ordering and renames unused navigation prop.
src/components/transaction/types/InvoiceTransaction.tsx Renames unused navigation prop to _navigation.
src/components/transaction/types/ExpensePayoutTransaction.tsx Renames unused navigation prop to _navigation.
src/components/transaction/types/DonationTransaction.tsx Renames unused navigation prop to _navigation.
src/components/transaction/types/CheckTransaction.tsx Renames unused navigation prop to _navigation.
src/components/transaction/types/CardChargeTransaction.tsx Renames unused navigation prop to _navigation.
src/components/transaction/types/BankFeeTransaction.tsx Renames unused navigation prop to _navigation.
src/components/transaction/types/BankAccountTransaction.tsx Renames unused navigation prop to _navigation.
src/components/transaction/types/AchTransferTransaction.tsx Renames unused navigation prop to _navigation.
src/components/transaction/Transaction.tsx Removes now-unnecessary @ts-expect-error for Icon glyph typing.
src/components/organizations/TransactionWrapper.tsx Removes unused import after navigation migration.
package-lock.json Lockfile updates reflecting dependency tree changes (dev flags/removed peers).
components/Navbar.tsx Narrows options typing and renames unused navigation prop.
app/login/index.tsx Removes dead navigation/SWR imports after router migration.
app/(app)/receipts/selection.tsx Extends parsed transaction typing and guards memo access with optional chaining.
app/(app)/cards/card-grants/[id].tsx Adds typed useLocalSearchParams to avoid `string
app/(app)/_layout.tsx Uses non-null assertion for SWRCacheProvider consumption (context provided by parent layout).
app/(app)/(events)/index.tsx Serializes fallback org data in navigation params for Expo Router.
app/(app)/(events)/[id]/transactions/index.tsx Types route params and parses serialized fallback org data for offline SWR.
app/(app)/(events)/[id]/index.tsx Types route params and parses serialized fallback org data; updates orgId typing.
app/(app)/(events)/[id]/donations/index.tsx Adds typed useLocalSearchParams for dynamic route param.
app/(app)/(events)/[id]/cards/order.tsx Prefixes intentionally-unused locals to satisfy lint rules.
app/(app)/(events)/[id]/account-numbers.tsx Types route params and parses serialized fallback org data for offline SWR.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +86 to +88
fallbackData: params.fallbackData
? (JSON.parse(params.fallbackData) as Organization | OrganizationExpanded)
: undefined,
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

params.fallbackData is parsed with JSON.parse without any error handling. If the route is opened from a deeplink with a malformed fallbackData value, this will throw and crash the page. Recommend checking typeof params.fallbackData === "string" and using a try/catch to fall back to undefined when parsing fails.

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +74
fallbackData: params.fallbackData
? (JSON.parse(params.fallbackData) as OrganizationExpanded)
: undefined,
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

params.fallbackData is parsed with JSON.parse without validating the input or handling malformed JSON. If a user opens this route via deeplink with an invalid fallbackData query param, the screen will throw during render. Consider guarding for typeof params.fallbackData === "string" and wrapping the parse in try/catch, defaulting to undefined when parsing fails.

Copilot uses AI. Check for mistakes.
organization={organization}
orgId={params.id}
isFirst={item.isFirst}
orgId={params.id as `org_${string}`}
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TransactionWrapper defaults isFirst to false, but this render path no longer passes item.isFirst. That likely regresses styling (top rounding/spacing) for the first transaction in a section and also defeats the component’s memoization that depends on isFirst. Pass isFirst={item.isFirst} here (similar to how mock transactions pass top={item.isFirst}).

Suggested change
orgId={params.id as `org_${string}`}
orgId={params.id as `org_${string}`}
isFirst={item.isFirst}

Copilot uses AI. Check for mistakes.
organization={organization}
orgId={params.id}
isFirst={item.isFirst}
orgId={params.id as `org_${string}`}
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using params.id as \org_${string}`removes type safety and can mask bad route params at runtime. SinceOrganization.idis already typed as a template literal, prefer typing the route params as{ id: org_${string}; ... }` so this component doesn’t need assertions and incorrect IDs are caught earlier.

Copilot uses AI. Check for mistakes.
<TapToPayBanner
onDismiss={handleDismissTapToPayBanner}
orgId={params.id}
orgId={params.id as `org_${string}`}
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casting params.id to org_${string} here hides the fact that the route param is currently typed as a plain string. Prefer updating useLocalSearchParams’ generic to { id: org_${string}; fallbackData?: string } so you don’t need repeated as assertions and you retain end-to-end type safety for org IDs.

Copilot uses AI. Check for mistakes.
Comment on lines 238 to 241
const baseParams = {
id: organization.id,
fallbackData: organization as unknown,
fallbackData: JSON.stringify(organization),
};
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serializing the entire organization object into route params (fallbackData) can leak sensitive fields (e.g., account_number/routing_number on OrganizationExpanded) into the URL/navigation state and can also create very large query strings. Prefer passing only the minimal primitives needed for rendering (e.g., id + name) and relying on SWR cache/offline cache for the full object, or explicitly stripping sensitive fields before stringifying.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +61
fallbackData: params.fallbackData
? (JSON.parse(params.fallbackData) as Organization | OrganizationExpanded)
: undefined,
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

params.fallbackData is parsed with JSON.parse without validating that it’s a single string or handling malformed JSON. A bad/deeplinked value (or repeated query param producing string[]) will throw and crash the screen. Consider guarding with typeof params.fallbackData === "string" and wrapping parsing in a try/catch (falling back to undefined on failure).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants