| name | ts-hooks-kit-react19-compat | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| overview | Create a phased roadmap to bootstrap `@ts-hooks-kit/core` from `usehooks-ts`, upgrade for React 19 compatibility first, then continue maintained API-compatible hook development with migration tooling. | ||||||||||||||||||||||||||||||||||||||||||
| todos |
|
||||||||||||||||||||||||||||||||||||||||||
| isProject | false |
- Ship
@ts-hooks-kit/coreas a maintained library based onusehooks-ts. - Phase 1: upgrade dependencies/tooling and verify React 19 compatibility first.
- Phase 2: continue hook updates/additions while preserving API compatibility semantics.
- Use new import path (
@ts-hooks-kit/core) with migration support fromusehooks-ts.
- Package name:
@ts-hooks-kit/core. - Bootstrap strategy: import/copy upstream
usehooks-tsbaseline, then upgrade. - Import compatibility: new package import path + codemod + migration docs (not strict old package path).
- Runtime/tooling baseline: modern stack (
Node >=20) is the default support target. - Fallback policy: users constrained to older Node should remain on upstream
usehooks-ts.
- tsdown is the successor to tsup, built on the Rust-based Rolldown engine (powers Vite 8).
- Near-identical config API to tsup —
tsdown migrateautomates conversion from upstream tsup config. - Faster builds and significantly faster
.d.tsgeneration (built-in, no separate rollup-dts step). - Produces ESM + CJS dual output with better CJS interop than esbuild.
- Fallback: if a pre-1.0 tsdown bug is hit, revert to tsup (same config format).
- Industry standard for published libraries (8/10 major React hook libraries use pnpm).
- Rock-solid npm publish pipeline — no registry,
.npmrc, or workspace protocol issues. - Strict dependency enforcement prevents phantom dependencies.
- Mature CI support (GitHub Actions
pnpm/action-setup).
Monorepo is needed because the project includes both a publishable package and a community docs site. Docs must stay in sync with code (atomic PRs for hook + doc changes). However, Turborepo/Nx are unnecessary for 2 packages — pnpm workspaces alone is sufficient.
Reference: TanStack Query, ahooks, shadcn/ui, and Mantine all use monorepo with docs co-located. This is the community standard for libraries with documentation sites.
ts-hooks-kit/
├── packages/
│ └── core/ # @ts-hooks-kit/core
│ ├── src/ # hooks source (preserves upstream layout)
│ ├── tsdown.config.ts
│ ├── vitest.config.ts
│ ├── tsconfig.json
│ └── package.json
├── apps/
│ └── docs/ # docs site (VitePress)
│ ├── .vitepress/
│ ├── guide/
│ └── package.json
├── pnpm-workspace.yaml # packages: ['packages/*', 'apps/*']
├── tsconfig.base.json # shared TypeScript config
├── .eslintrc.js # shared lint config
├── package.json # root scripts
├── docs/ # non-site docs (migration.md, compatibility.md)
└── CHANGELOG.md
Root scripts (no Turborepo needed):
{
"scripts": {
"build": "pnpm -r build",
"test": "pnpm --filter @ts-hooks-kit/core test",
"test:codemod": "pnpm --filter @ts-hooks-kit/codemod test",
"dev:docs": "pnpm --filter @ts-hooks-kit/docs dev",
"lint": "pnpm -r lint",
"codemod": "node packages/codemod/bin/ts-hooks-kit-codemod.js",
"migrate:test": "node packages/codemod/bin/ts-hooks-kit-codemod.js examples/sample-app --pattern \"**/*.{ts,tsx,cjs}\" --dry"
}
}Upstream carries lodash.debounce as a production dependency. Decision: replace with a lightweight internal debounce utility (~30 lines).
Rationale:
lodash.debouncewas last published in 2021 — effectively unmaintained.- No ESM export — causes bundler warnings and CJS interop friction.
- Pulls in
lodash._rootinternal dependency. - ~1.5 KB for functionality that takes ~0.3 KB to implement.
- A hooks library should minimize its dependency tree.
The internal implementation must support the full API surface used by useDebounceCallback:
- Basic delay-based debouncing
leading/trailingoptionsmaxWaitoption.cancel()and.flush()control methods
This makes @ts-hooks-kit/core a zero-dependency package (React as peer only).
Implementation: Phase 1, as part of the dependency audit. Must pass all existing useDebounceCallback and useDebounceValue tests with no behavioral changes.
Upstream usehooks-ts already declares ^19 in peerDependencies. Phase 1 is therefore focused on validating runtime behavior against React 19 (not just declaring peer support), specifically:
- Upgrading
@testing-library/reactfrom v14 → v16 (React 19 compatible) - Upgrading
@types/reactfrom18.2.73→^19 - Auditing hooks for effect timing, SSR, and deprecated pattern differences
Reference baseline source:
[/Users/mac/WebApps/oss/custom-hooks-ts/usehooks-ts/packages/usehooks-ts/package.json](/Users/mac/WebApps/oss/custom-hooks-ts/usehooks-ts/packages/usehooks-ts/package.json)
Context7 checks used:
- React library ID:
/facebook/react(versions includev19_2_0) - Vitest library ID:
/vitest-dev/vitest(versions includev4.0.7) - Testing Library docs library ID:
/testing-library/testing-library-docs
Planned dependency targets for Phase 1:
reactpeer range: include^19.2.0while keeping backward-compatible range in first compatibility release- candidate peer:
^18 || ^19
- candidate peer:
react-dompeer: add only if runtime hooks require it; otherwise keep package React-only to match upstream style@types/react: move from18.2.73baseline to^19@types/react-dom: add^19only if test/app harness requires direct DOM typingsvitest: upgrade from^1.3.1baseline to^4.0.7for active maintenance- constraint: Vitest v4 requires Node
>=20and Vite>=6
- constraint: Vitest v4 requires Node
@testing-library/reactand@testing-library/jest-dom: upgrade to current React 19-compatible majors during Phase 1 test-matrix setuptypescript: keep at least upstream baseline^5.3.3; prefer newer stable if required by React 19 types/test stack
Dependency validation gate (must pass before Phase 2):
- Lock final versions in
package.jsonand capture rationale indocs/compatibility.md - Run matrix tests on React 18 and React 19 with the final dependency set
- Confirm no API signature drift in exported hooks after dependency upgrades
- Confirm migration docs state Node support policy and explicit fallback path to upstream
usehooks-tsfor legacy Node environments
Phase 0 checklist:
- Initialize pnpm monorepo workspace structure (see "Repository structure" above).
- Set up
packages/core/with tsdown build config (migrate from upstream tsup config viatsdown migrate). - Import upstream source baseline from
usehooks-tsrelease line (pin exact upstream tag/commit in docs). - Preserve upstream hook filenames/exports layout initially to minimize diff noise.
- Set up CI pipeline (GitHub Actions):
- Build + test on push/PR
- React 18 + React 19 test matrix from day one
- Node 20 runner
- Scaffold
apps/docs/with chosen docs framework (framework decision TBD). - Create foundational docs:
-
[/Users/mac/WebApps/oss/custom-hooks-ts/ts-hooks-kit/docs/migration.md](/Users/mac/WebApps/oss/custom-hooks-ts/ts-hooks-kit/docs/migration.md) -
docs/compatibility.md -
CHANGELOG.md
-
Deliverable:
- Buildable baseline package with unchanged API surface behavior (before React 19 changes).
- CI pipeline running tests against React 18 + 19.
- Monorepo structure with docs site scaffold.
Note: upstream already declares ^19 in peerDependencies. This phase validates actual runtime compatibility, not just peer declaration.
- Update package/runtime constraints:
peerDependencies: React support includes 19 (^18 || ^19in first release).- Type dependencies move to React 19-compatible set (
@types/react→^19).
- Upgrade test stack for React 19 runtime validation:
@testing-library/reactv14 → v16 (React 19 compatible)vitest^1.3.1 → ^4.0.7 (requires Vite >=6, Node >=20)@testing-library/jest-domto current React 19-compatible major
- Update build config: tsdown (migrated from upstream tsup).
- Audit hooks with React-sensitive behavior and patch as needed (effects timing assumptions, SSR-safe guards, deprecated patterns).
- Replace
lodash.debouncewith internal debounce utility (~30 lines, zero dependencies). Must pass all existing debounce hook tests. - Run full compatibility test matrix:
- React 18 + React 19
- TypeScript versions you support
- SSR/basic hydration smoke checks
- Begin migration guide and codemod alongside this phase (moved from Phase 4 — the import rewrite is trivial and benefits early adopters).
- Publish first maintained release candidate under
@ts-hooks-kit/core.
Deliverable:
- React 19-compatible stable baseline with parity-focused behavior.
- Draft migration guide and working codemod available for early testing.
- Freeze and document public API contract from imported baseline:
- exported hook names
- function signatures/types
- module entry points
- Add automated API checks:
- export snapshot test
- type-level contract tests for critical hooks
- Define compatibility policy:
- additive changes in minor
- breaking changes only in major with migration notes
Deliverable:
- CI-enforced API compatibility safety net for future development.
Status: Completed — 17 new hooks added following strict TDD (Test-Driven Development).
New hooks implemented (all with full TypeScript support, tests, and React 18/19 compatibility):
| Hook | Description | API |
|---|---|---|
usePrevious |
Track previous state/props value | const prev = usePrevious(value, initial?) |
useSet |
Manage Set data structure with reactive updates | const [set, { add, remove, toggle, has, clear, reset }] |
useQueue |
FIFO queue data structure management | const [queue, { add, remove, clear, first, last, size }] |
useList |
Enhanced array state management | const [list, { set, push, updateAt, insertAt, removeAt, clear, reset }] |
useAsync |
Async function state with loading/error | const { value, error, loading, retry } = useAsync(fn, deps?) |
useUpdateEffect |
useEffect that skips initial mount | useUpdateEffect(effect, deps) |
useThrottle |
Throttle execution (fn + value variants) | useThrottleFn(fn, wait) / useThrottle(value, wait) |
useMemoizedFn |
Stable function reference without deps | const stableFn = useMemoizedFn(fn) |
| Hook | Description | API |
|---|---|---|
useGeolocation |
Browser geolocation API wrapper | const { latitude, longitude, accuracy, loading, error } |
useNetwork |
Network status monitoring | const { online, effectiveType, downlink } = useNetwork() |
usePermission |
Browser permissions API | const { state, supported } = usePermission(name) |
usePageLeave |
Detect when user leaves page | usePageLeave(handler) |
useIdle |
Detect user idle state | const { idle, lastActive } = useIdle(timeout, options?) |
useUpdate |
Force component re-render | const update = useUpdate() |
| Hook | Description | API |
|---|---|---|
useStateList |
Navigate through list of states | const { state, next, prev, setState, isFirst, isLast } |
usePagination |
Pagination logic with range generation | const { activePage, range, setPage, next, prev, first, last } |
useDisclosure |
Modal/drawer disclosure state | const [opened, { open, close, toggle }] = useDisclosure() |
Testing Summary:
-
All 17 new hooks implemented via strict TDD (Red-Green-Refactor)
-
274 total tests passing (including 17 new test files)
-
Zero breaking changes to existing 33 hooks
-
Zero new runtime dependencies (React peer only)
-
Compare periodically against upstream
usehooks-tschanges and backport relevant fixes. -
Add new hooks under clear policy:
- no breaking behavior to existing hooks
- consistent naming/docs/testing standards
-
Versioning/release cadence with changelog discipline.
Deliverable:
- Actively maintained fork-plus evolution path while preserving compatibility expectations.
Status: Completed
Note: Migration guide and codemod work begins in Phase 1. This phase is finalized and published.
- Migration guide completed in
docs/migration.mdwith:- old import -> new import examples
- known behavior differences
- version mapping table (
usehooks-tsbaseline to@ts-hooks-kit/core) - migration validation checklist
- Codemod finalized in
packages/codemod/for import rewrite:from "usehooks-ts"->from "@ts-hooks-kit/core"- supports
--drymode and--patternfiltering
- Migration docs published on docs site in
apps/docs/guide/migration.md. - Codemod verified on sample app at
examples/sample-app/.
Deliverable:
- Low-friction migration path with minimal manual edits.
- Migration docs published on docs site.
- End-to-end codemod validation completed on sample app.
Named imports:
// before
import { useLocalStorage, useBoolean } from 'usehooks-ts'
// after
import { useLocalStorage, useBoolean } from '@ts-hooks-kit/core'Namespace imports:
// before
import * as Hooks from 'usehooks-ts'
// after
import * as Hooks from '@ts-hooks-kit/core'Type imports:
// before
import type { UseBooleanReturn } from 'usehooks-ts'
// after
import type { UseBooleanReturn } from '@ts-hooks-kit/core'CommonJS require:
// before
const hooks = require('usehooks-ts')
// after
const hooks = require('@ts-hooks-kit/core')| usehooks-ts baseline | @ts-hooks-kit/core | Migration notes |
|---|---|---|
3.1.1 |
0.1.0 |
Source baseline pinned from upstream usehooks-ts@3.1.1, plus React 19 validation and 17 additional hooks |
- Package name changes from
usehooks-tsto@ts-hooks-kit/core; migration is import-path-only for baseline hooks. @ts-hooks-kit/coreofficially supports React^18 || ^19with CI matrix validation for React 18 and 19.- Debounce internals use an in-repo implementation instead of
lodash.debounce, while preserving the existinguseDebounceCallbackanduseDebounceValuecontract. @ts-hooks-kit/coreincludes 17 new hooks added in Phase 3; existing upstream baseline hooks remain compatibility-focused.
Use the migration codemod from repository root:
node packages/codemod/bin/ts-hooks-kit-codemod.js <target-path> --dry
node packages/codemod/bin/ts-hooks-kit-codemod.js <target-path>Default file glob:
**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts}
- Run codemod with
--dryand review planned rewrites. - Run codemod without
--dryand confirm allusehooks-tsimports are replaced. - Search codebase for any remaining
usehooks-tsreferences. - Install
@ts-hooks-kit/coreand removeusehooks-tsfrom dependencies. - Run application test suite and ensure no regressions.
- Run TypeScript type-check and ensure there are no import/type errors.
- Verify runtime behavior for hooks that depend on timers/storage/media queries.
- Update internal docs/snippets that still reference old package imports.
flowchart TD
phase0[Phase0_Bootstrap<br/>pnpm monorepo + tsdown + CI] --> phase1[Phase1_React19_Validation<br/>+ migration draft]
phase1 --> phase2[Phase2_API_Guardrails]
phase2 --> phase3[Phase3_Updates_NewHooks]
phase2 --> phase4[Phase4_Migration_Finalization]
phase3 --> releaseReady[ReleaseReady]
phase4 --> releaseReady
- Package
@ts-hooks-kit/corebuilds (via tsdown), tests (via Vitest v4), and type-checks. - Monorepo structure with pnpm workspaces:
packages/core/+apps/docs/. - React 19 is officially supported and validated in CI (React 18 + 19 matrix).
- Existing baseline hooks preserve API signatures and expected behavior.
- Migration doc + codemod are available and tested on at least one sample app.
- Docs site is deployed and includes migration guide.
- Release notes clearly communicate compatibility guarantees and upgrade steps.