Skip to content

feat: add optional @types/react peer dependency - #2722

Open
unrevised6419 wants to merge 1 commit into
streamich:masterfrom
unrevised6419:pr/optional-types-react-peer
Open

unrevised6419 wants to merge 1 commit into
streamich:masterfrom
unrevised6419:pr/optional-types-react-peer

Conversation

@unrevised6419

@unrevised6419 unrevised6419 commented Sep 24, 2026 •

Copy link
Copy Markdown

Description

react-use ships lib/index.d.ts / esm/index.d.ts whose declarations import from react, but package.json declares only the react runtime peer. That is fine when the package is installed inside the consumer's node_modules, and broken when it is not.

Under pnpm's virtualStoreType: global, the package physically lives outside the consumer's repository, e.g. ~/Library/pnpm/store/v11/links/@/react-use/17.6.1/<hash>/node_modules/react-use. TypeScript resolves a package's imports from where that package physically sits and ignores NODE_PATH, so import ... from 'react' inside the shipped .d.ts resolves to the untyped react/index.js (silently accepted under allowJs) rather than to a declaration file:

======== Resolving module 'react' from '<store>/react-use/lib/index.d.ts'. ========
======== Module name 'react' was successfully resolved to '<store>/react/index.js' with Package ID 'react/index.js@19.3.0'. ========

index.js, not index.d.ts β€” that is the bug. Everything those declarations feed then degrades to any, with zero compiler errors. In one real consuming app, 38 React type resolution sites coming from react-use landed on JS this way.

This PR adds @types/react as an optional peer dependency at "*", which is enough for TypeScript to find the types from the package's own location:

"peerDependencies": { "@types/react": "*" },
"peerDependenciesMeta": { "@types/react": { "optional": true } }

Why it is safe

  • Optional β€” consumers who do not use TypeScript see no install warning and get nothing new in their lockfile.
  • "*" β€” no version claim is introduced, so it resolves against whatever @types/react the consumer already has and cannot conflict with it. Note this repo develops against @types/react@17; "*" deliberately does not imply React 18/19 either way, matching the existing "react": "*" peer.
  • Runtime behaviour of the package does not change at all. This is a package.json metadata change only β€” no source, build output or API surface is touched.

Precedent: @testing-library/react already declares this same pair of fields for the same reason (at ^18.0.0 || ^19.0.0, since it supports two React majors; react-use's own react peer is *).

Verified end to end on a real application: adding these peers via pnpm packageExtensions took it from 61 untyped + 6 unresolved React resolutions to 1012/1012 resolutions landing on .d.ts, with tsc still exiting 0.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as before)

Checklist

  • Read the Contributing Guide
  • Perform a code self-review
  • Comment the code, particularly in hard-to-understand areas (n/a β€” package.json metadata only)
  • Add documentation (n/a)
  • Add hook's story at Storybook (n/a)
  • Cover changes with tests (n/a β€” no runtime behaviour changes)
  • Ensure the test suite passes (yarn test) (unchanged; no source touched)
  • Provide 100% tests coverage (n/a)
  • Make sure code lints (yarn lint) (no linted source changed)
  • Make sure types are fine (yarn lint:types) (no TypeScript changed)

The shipped .d.ts files import from 'react', but only the react runtime
peer is declared. Under package layouts where react-use is installed
outside the consumer's tree (pnpm virtualStoreType: global), TypeScript
resolves that import from where react-use physically sits and lands on
react/index.js instead of a declaration file, silently degrading every
type fed by those declarations to any.

Declaring @types/react as an optional peer at "*" makes the types
resolvable without introducing a version claim or affecting
non-TypeScript consumers.
@unrevised6419
unrevised6419 force-pushed the pr/optional-types-react-peer branch from 118fc0a to 8f2333d Compare September 24, 2026 03:08
@unrevised6419
unrevised6419 marked this pull request as ready for review September 24, 2026 03:26

This branch has not been deployed

No deployments
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