Skip to content

fix: detect useCallback methods in imperative handles - #1139

Open
askalf wants to merge 6 commits into
reactjs:mainfrom
askalf:fix/imperative-handle-callback-methods
Open

askalf wants to merge 6 commits into
reactjs:mainfrom
askalf:fix/imperative-handle-callback-methods

Conversation

@askalf

@askalf askalf commented Sep 20, 2026

Copy link
Copy Markdown

Fixes #856

Summary

  • Resolve the function wrapped by React useCallback when documenting component methods.
  • Use that shared resolution for both method admission and signature extraction.
  • Add coverage across imperative handles, object/statics/class/assignment surfaces and negative controls.

Decisions

Resolution intentionally unwraps one React useCallback layer only; recursively unwrapping or treating other React builtins as methods would broaden behavior beyond this defect. The package suite and formatting checks passed.

AI assistance: this bug was found and the fix and tests were drafted with AI tooling in my workflow; the tests and checks above were executed as pasted. I'm responsible for the change and will handle review feedback.

askalf and others added 5 commits September 19, 2026 05:11
The handler recognised a useCallback-wrapped property as a method, but
the documentation was built from the call expression, so the method
came out with no parameters and no return type. resolveToMethodFunction
now resolves a value to the function it documents, unwrapping a React
useCallback call, and both the handler's method test and the
documentation builder use it. The tests assert the wrapped function's
signature and cover a local function named useCallback, a call with no
arguments and a non-function argument.
The handler's unwrapping now runs for every method node path, so add the
surfaces it reaches beyond the imperative handle identifier: a callback
written inline in the handle object, an ObjectExpression component, a
statics object, a class property and a Component.foo assignment, plus the
docblock and the async/generator modifiers of the wrapped function, a
renamed useCallback import and a handle that precedes the declaration.
The controls pin the guards the unwrapping keeps: a local useCallback, a
missing or non-function argument, a spread argument, a nested call and
useMemo.
Every positive callback fixture carried a typed parameter and a return
annotation, so the empty-signature path the boundary ledger claims was
never exercised. Admit useCallback(() => {}, []) through
useImperativeHandle and assert an empty params list and a null return.
@changeset-bot

changeset-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a9605a4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
react-docgen Patch
@react-docgen/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify

netlify Bot commented Sep 20, 2026

Copy link
Copy Markdown

Deploy Preview for react-docgen canceled.

Name Link
🔨 Latest commit a9605a4
🔍 Latest deploy log https://app.netlify.com/projects/react-docgen/deploys/6aaf375b91c0cf000803866b

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.

useCallback + useImperativeHandle methods

1 participant