Skip to content

fix(types): support React Native 0.87 Strict TypeScript API - #697

Open
jslok wants to merge 1 commit into
gre:masterfrom
jslok:fix/rn-087-strict-typescript-api
Open

fix(types): support React Native 0.87 Strict TypeScript API#697
jslok wants to merge 1 commit into
gre:masterfrom
jslok:fix/rn-087-strict-typescript-api

Conversation

@jslok

@jslok jslok commented Sep 9, 2026

Copy link
Copy Markdown

RN 0.87 makes the Strict TypeScript API the default. Two type-level assumptions in this package break under it, and because package.json exposes src/index.tsx through the react-native export condition, consuming apps see the errors in their own tsc run:

node_modules/react-native-view-shot/src/specs/NativeRNViewShot.ts(3,34): error TS2307:
  Cannot find module 'react-native/Libraries/Types/CodegenTypes'
node_modules/react-native-view-shot/src/index.tsx(352,31): error TS2345:
  Argument of type '(props: ...) => ReactNode' is not assignable to parameter of type 'CaptureTarget'
node_modules/react-native-view-shot/src/index.tsx(439,9): error TS2322:
  Type '(node: View | null) => void' is not assignable to type 'Ref<ReactNativeElement>'

1. CodegenTypes deep import. RN's exports map now sets "./Libraries/*": { "types": null } unless the consumer opts into the react-native-legacy-deep-imports condition, so the deep import has no types. RN re-exports the same declarations as a CodegenTypes namespace from the package root. CodegenTypes.WithDefault<number, -1> resolves to exactly the same type as before (number | null | undefined), so the generated native signature is unchanged.

2. View as a ref instance type. Under the strict typings View is a function component rather than a class, so it no longer describes an instance. React.ComponentRef<typeof View> extracts the instance type and resolves correctly under both the legacy and the strict typings, so this is not an RN-version-gated change.

Compatibility note

The CodegenTypes namespace export landed in RN 0.80 (types_generated/Libraries/Types/CodegenTypesNamespace.d.ts); the current peer range is >=0.76.0. In practice the TurboModule spec only matters on the New Architecture, and v5's stack targets 0.81+, so I don't think anyone is affected — but if you'd rather not move the floor at all, the alternative is inlining target: number | null | undefined and dropping the import entirely. Happy to switch if you prefer that.

Verification

tsc --noEmit is clean against react-native@0.87.1 + typescript@6.0.3 in an app using both captureRef() and <ViewShot>, with no customConditions opt-out. No runtime code changed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01C55VgRJc8C6jJdtq1xZgLe

RN 0.87 makes the Strict TypeScript API the default, which breaks two
type-level assumptions in this package:

- `react-native/Libraries/*` subpaths now resolve to `types: null`, so the
  deep `CodegenTypes` import has no types. RN re-exports the same types as a
  `CodegenTypes` namespace from the package root; `WithDefault<number, -1>`
  resolves identically, so codegen output is unchanged.
- `View` is a function component, not a class, so it is no longer usable as
  a ref instance type. `React.ComponentRef<typeof View>` resolves to the
  instance type under both the legacy and strict typings.

Verified with `tsc --noEmit` against react-native 0.87.1 in an app that uses
both `captureRef` and `<ViewShot>`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C55VgRJc8C6jJdtq1xZgLe
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.

1 participant