The single native pass resolved [".ios", ".android", ".native", ""],
which models a platform that does not exist - on iOS Metro never falls
back to .android files and vice versa. Replace it with
tsconfig.check.ios.json and tsconfig.check.android.json, each mirroring
Metro's real resolution order for its platform, alongside the existing
web pass. pnpm typecheck now runs all three, and the lint workflow
matrix runs them as separate jobs.
The ambient check shims in src/platform are now excluded from passes
they aren't written for (previously the web shims were silently included
in the native pass via the "src" include glob), and a new Android-pass
shim pins react-native-device-attest to its platform-neutral base class,
whose Android variant omits the iOS-only getDeviceCheckToken static.
The Android pass surfaced a real bug: Referrer.getReferrerInfo() is
async on Android (the Play referrer API only exposes a promise) but sync
on iOS/web, and the shared callers used it synchronously - so on Android
the deepLink:referrerReceived metric fired with a Promise instead of
data. The API is now uniformly promise-returning and the callers await
it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCuMKXWHuyGoNhTVAHBMyk
The main typecheck models native resolution (.ios/.android/.native), so
.web variants were never checked in their real resolution context. Add a
second pass that roots the program at the web entry point and resolves
with moduleSuffixes [".web", ""], wire it up as pnpm typecheck:web, and
add it to the lint workflow matrix.
Ambient shims (src/platform/*.web-check.d.ts, web pass only) pin
react-native-svg, expo-file-system, and expo-image-manipulator to their
native declarations, since their .web.d.ts files expose a different API
surface than the one the app is written against (and, for
expo-file-system/legacy, raw package sources that break under suffix
remapping).
The rest fixes the drift the new pass surfaced, notably:
- List.web: ListRef now carries ListMethods (was RefObject<View>),
scrollToOffset accepts optional animated, ListProps defaults ItemT
- Dialog.web: ScrollableInner accepts a (never-attached) ScrollView ref,
InnerFlatList label optional + ListMethods ref, Handle accepts props
- Menu.web exports MenuControlProps; ContextMenu.web gets a properly
typed Trigger wrapper and accepts align
- Pager/TabBar/PagerWithHeader web variants align with the shared
contract (testID, onTabPressed, drag shared values, setMinimumHeight)
- useNavigationTabState.web now reports isAtFeeds/isAtBookmarks, fixing
drawer highlighting for those routes on web
- Web-only throw-stubs get real signatures; duplicated prop types move
into .shared.ts files (CaptchaWebView, EditImageDialog, OpenCameraBtn,
GestureActionView, ValuePropositionPager)
- findListNativeTag helper replaces findNodeHandle casts on List refs
- Assorted call-site type fixes (keyExtractor params, PostQuotes record
narrowing, saveBytesToDisk bytes param, openCamera web signature)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCuMKXWHuyGoNhTVAHBMyk