Skip to content

feat: support react-native-gesture-handler v3 - #26

Open
pawicao wants to merge 2 commits into
mainfrom
worktree-rngh-v3-support
Open

feat: support react-native-gesture-handler v3#26
pawicao wants to merge 2 commits into
mainfrom
worktree-rngh-v3-support

Conversation

@pawicao

@pawicao pawicao commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Purpose

This change adds support for react-native-gesture-handler v3. The library
continues to support v2. The peer range becomes ^2.0.0 || ^3.0.0.

No source code changes are necessary. The reasons are below.

Why the source code does not change

The library uses five symbols from Gesture Handler:

Symbol Kind Location
Gesture value HeaderPanBoundary.tsx
GestureDetector value HeaderPanBoundary.tsx
GestureHandlerRootView value HeaderPanBoundary.tsx
GestureStateChangeEvent type types.ts
PanGestureHandlerEventPayload type types.ts

v3 exports all five symbols from the package root. The names do not change.
The payload types keep the same shape.

v3 changes GestureDetector. The root export is now the v3 detector. This
detector accepts a gesture from either API. It sends a legacy gesture to the
legacy detector:

if (props.gesture instanceof ComposedGesture || props.gesture instanceof BaseGesture) {
  return <LegacyGestureDetector {...props} />;
}
return <NativeDetector {...props} />;

v3 also renames part of the v2 surface to Legacy* names. These renames apply
to components and to gesture instance types. The library does not import these
items.

The library keeps the legacy gesture API. Do not migrate to the v3
usePanGesture hook. A migration makes version-conditional code necessary.

How CI enforces the peer range

This change adds a gesture-handler-compat job. The job runs a matrix over
both majors. Each leg installs one major. Then each leg runs yarn typecheck
and yarn test.

yarn typecheck is the important step. src/ holds .ts files.
Therefore skipLibCheck does not hide a missing Gesture Handler export.
The shipped .d.ts imports come from the same statements in src/.

The matrix tracks each major by tag. It does not pin a patch version. An
upstream release that breaks the range then fails in CI. Users do not find the
failure first.

A consumer type test is not possible

I built a consumer-side type test. Then I removed it. The test cannot fail
when it must fail.

An unresolved import inside a .d.ts becomes the TypeScript error type.
TypeScript hides subsequent errors from the error type. Therefore no assertion
detects the problem. This includes 0 extends 1 & T detection of any.

I confirmed this behaviour. I pointed the built types.d.ts at an export that
does not exist. The test still passed.

The same break in src/types.ts gives a clear failure:

error TS2305: Module '"react-native-gesture-handler"' has no exported member ...

For this reason, yarn typecheck is the guarantee. The workflow file records
this reason. Do not add the fixture again.

skipLibCheck: false is not possible with v3

v3 ships specs/RNGestureHandlerDetectorNativeComponent.d.ts. Its
NativeProps does not extend the React Native ViewProps type. This gives
error TS2430 inside react-native-gesture-handler.

This problem is independent of Header Motion. No change in this repository can
correct it. Therefore skipLibCheck: true is the supported configuration. This
value is also the React Native template default.

The FAQ records this limit.

Development versions

The pinned devDependency moves to 3.2.1. The example app also moves to 3.2.1.
Local development then uses the v3 code path.

The example app is important here. Unit tests replace Gesture Handler with a
mock. Therefore the tests do not run the LegacyGestureDetector branch. The
example app is the only place that runs this branch.

The v2 leg of the matrix stays correct. That leg overrides only the root
devDependency. yarn typecheck excludes example. Jest ignores
example/node_modules. I simulated this install. The root resolved v2.
yarn typecheck and yarn test passed.

Verification

I ran these commands against 2.30.0, 2.32.0, and 3.2.1:

  • yarn lint — pass. Two warnings exist in docs/. They are not new.
  • yarn typecheck — pass.
  • yarn test — pass. 38 tests.
  • yarn prepare — pass.
  • npx tsc --noEmit in example/ — pass.

Open item

No test runs v3 on a device. Please run the example app and use a pannable
header. This action exercises the LegacyGestureDetector branch at runtime.

🤖 Generated with Claude Code

pawicao and others added 2 commits August 15, 2026 01:20
Widen the Gesture Handler peer range to `^2.0.0 || ^3.0.0`. No source
changes were needed: every symbol this library uses is still exported from
the v3 package root under the same name, and v3's `GestureDetector` accepts
legacy gestures and dispatches to the legacy detector at runtime.

The v3 `Legacy*` renames only touched components and gesture instance types,
none of which we import. Our public type surface reaches Gesture Handler on
a single line — the `GestureStateChangeEvent` / `PanGestureHandlerEventPayload`
import in `types.ts` — and both are root exports in v2 and v3 with identical
payload shapes.

Add a `gesture-handler-compat` CI matrix over both majors. `yarn typecheck`
is the step that actually enforces the range: `src/` is `.ts`, so a missing
Gesture Handler export fails there even under `skipLibCheck: true`. A
consumer-side type test was prototyped and dropped — in a `.d.ts` an
unresolved import silently widens to the error type, which defeats every
assertion, including `0 extends 1 & T` any-detection.

Verified `lint`, `typecheck`, `test`, `prepare`, and the example app's
typecheck against both 2.30.0 and 3.2.1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Move the pinned devDependency and the example app to 3.2.1, so local
development and the example exercise the v3 code path. This matters for the
example in particular: v3's `GestureDetector` routes legacy gestures to
`LegacyGestureDetector` at runtime, and unit tests mock Gesture Handler
entirely, so the example is the only place that branch runs for real.

The `gesture-handler-compat` matrix keeps v2 covered. Its v2 leg overrides
only the root devDependency, which is enough: `yarn typecheck` excludes
`example` and Jest ignores `example/node_modules`, so the example's v3 pin
does not leak into the v2 leg. Verified by simulating that install locally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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