Skip to content

chore: convert library from Flow to TypeScript#260

Merged
STRML merged 1 commit into
masterfrom
2026-05-typescript-conversion
May 12, 2026
Merged

chore: convert library from Flow to TypeScript#260
STRML merged 1 commit into
masterfrom
2026-05-typescript-conversion

Conversation

@STRML
Copy link
Copy Markdown
Collaborator

@STRML STRML commented May 11, 2026

Summary

Migrate lib/ and __tests__/ from Flow to TypeScript. Public runtime API (and PropTypes validation) is unchanged.

  • Replace @babel/preset-flow with @babel/preset-typescript
  • Convert lib/*.js to *.ts/*.tsx with explicit types
  • Add lib/index.ts for the typed entry-point
  • Drop flow-bin, flow-typed/, .flowconfig, all // @flow pragmas
  • Add tsconfig.json (typecheck), tsconfig.build.json (declaration emit), tsconfig.test.json
  • build.sh now runs babel + tsc --emitDeclarationOnly to produce .js + .d.ts
  • ESLint switched to @typescript-eslint/parser for .ts/.tsx
  • Tests renamed to .test.tsx / .test.ts; jest picks them up via babel
  • package.json gains a typecheck script and a types: "./build/index.d.ts" field

Why now

Flow is no longer well-supported in the React ecosystem and most consumers expect TypeScript declarations. Pinning to flow-bin@0.153.0 (a 2020 build) was holding back tooling upgrades and providing zero value to downstream TS users.

Test plan

  • yarn install
  • yarn typechecktsc --noEmit clean
  • yarn lint — 0 errors (1 pre-existing jest/expect-expect warning)
  • yarn test — 50/50 tests pass, snapshots regenerated and equivalent
  • yarn build — emits build/{Resizable,ResizableBox,propTypes,utils,index}.{js,d.ts}
  • Sanity-check that a downstream TS consumer gets proper IntelliSense from import {Resizable} from 'react-resizable'

Notes

  • Snapshot files were renamed alongside their .test.tsx counterparts. Diff shows the underlying rendered output is unchanged.
  • The /goal slash command used to scope this work lives at .claude/commands/goal.md.

Summary by CodeRabbit

  • New Features

    • Adds TypeScript declaration files for improved IDE autocompletion and type checking.
  • Chores

    • Migration from Flow to TypeScript across the codebase and toolchain.
    • Build, lint, test, and bundler configurations updated to support TypeScript.
  • Tests

    • Updated tests and fixtures to align with revised sizing/typing behavior.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 36aff848-a9fb-412a-a72c-130ec9db4ac0

📥 Commits

Reviewing files that changed from the base of the PR and between f373c31 and 9c19c68.

⛔ Files ignored due to path filters (3)
  • __tests__/__snapshots__/Resizable.test.tsx.snap is excluded by !**/*.snap
  • __tests__/__snapshots__/ResizableBox.test.tsx.snap is excluded by !**/*.snap
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (21)
  • .babelrc
  • .claude/commands/goal.md
  • .flowconfig
  • __tests__/Resizable.test.tsx
  • __tests__/ResizableBox.test.tsx
  • __tests__/ssr.test.ts
  • build.sh
  • eslint.config.js
  • flow-typed/npm/jest_v26.x.x.js
  • jest.config.js
  • lib/Resizable.tsx
  • lib/ResizableBox.tsx
  • lib/index.ts
  • lib/propTypes.ts
  • lib/utils.js
  • lib/utils.ts
  • package.json
  • tsconfig.build.json
  • tsconfig.json
  • tsconfig.test.json
  • webpack.config.js
💤 Files with no reviewable changes (3)
  • .flowconfig
  • lib/utils.js
  • flow-typed/npm/jest_v26.x.x.js
✅ Files skipped from review due to trivial changes (5)
  • tsconfig.test.json
  • tsconfig.json
  • lib/index.ts
  • .babelrc
  • .claude/commands/goal.md
🚧 Files skipped from review as they are similar to previous changes (10)
  • lib/utils.ts
  • tests/ResizableBox.test.tsx
  • webpack.config.js
  • tsconfig.build.json
  • jest.config.js
  • package.json
  • lib/ResizableBox.tsx
  • lib/propTypes.ts
  • eslint.config.js
  • lib/Resizable.tsx

📝 Walkthrough

Walkthrough

Migrates react-resizable from Flow to TypeScript: adds tsconfigs, swaps Babel preset to TypeScript, converts types and components to TS/TSX, updates ESLint/Jest/build scripts, adjusts tests for refactored dimension logic, and removes Flow artifacts and definitions.

Changes

Flow-to-TypeScript Conversion

Layer / File(s) Summary
Migration Plan
.claude/commands/goal.md
Documents the migration goal, constraints (no runtime changes, preserve PropTypes and build output), acceptance criteria, step-by-step plan, and out-of-scope items.
TypeScript Configuration
tsconfig.json, tsconfig.build.json, tsconfig.test.json
Adds three TypeScript configurations: base config with ES2020/ESNext target and relaxed strictness; build config for declaration-only output to ./build; test config for test sources with noEmit: true.
Babel and Webpack Setup
.babelrc, webpack.config.js
Updates Babel preset from @babel/preset-flow to @babel/preset-typescript. Extends webpack Babel loader and module resolution to match .ts and .tsx extensions.
ESLint Configuration
eslint.config.js
Adds TypeScript parser (@typescript-eslint/parser) and plugins (@typescript-eslint, react, jest) for TS/TSX files. Adjusts globals and disables/overrides rules like no-unused-vars and no-explicit-any for the TS config block.
Type System
lib/propTypes.ts
Converts Flow type annotations to TypeScript: updates ReactRef, ResizableState, ResizableBoxState, callback data types, DefaultProps, ResizeHandleFn, and Props; adjusts PropTypes validator signatures.
Resizable Component
lib/Resizable.tsx
Converts from Flow to TypeScript: changes state type from void to {}; retyps instance fields (handleRefs, lastHandleRect, slack, lastSize); refactors resizeHandler to capture baseWidth/baseHeight from lastSize ?? props and use that base for dimension-change detection; updates renderResizeHandle and render() with typed refs and casts.
ResizableBox Component
lib/ResizableBox.tsx
Converts ResizableBoxProps from Flow exact object to Omit<ResizableProps, 'children'> with explicit optional fields; re-types getDerivedStateFromProps and converts onResize to a typed arrow function; adjusts render() prop passing with type casts.
Public API
lib/index.ts
Exports Resizable and ResizableBox components and re-exports TypeScript types (Axis, DefaultProps, DragCallbackData, Props, ReactRef, ResizableBoxState, ResizableState, ResizeCallbackData, ResizeHandleAxis).
Utilities
lib/utils.ts, lib/utils.js
Removes Flow-typed lib/utils.js. Adds TypeScript lib/utils.ts exporting cloneElement function that merges style and concatenates className before cloning.
Build Pipeline
build.sh, package.json
build.sh clears ./build, transpiles TS/TSX via Babel, and emits declarations via tsc --project tsconfig.build.json. package.json adds types field, introduces typecheck script, updates preversion to run lint and typecheck, adds TypeScript/ESLint devDependencies, and removes Flow tooling.
Test Infrastructure
jest.config.js, __tests__/Resizable.test.tsx, __tests__/ResizableBox.test.tsx
Updates Jest to target lib/*.{ts,tsx} in coverage collection, include TS extensions in module resolution, and exclude flow-typed. Adjusts resize-behavior test assertions for nw, sw, ne, se handles and transformScale case to match refactored dimension-comparison logic; updates stale-props west-handle test. Re-types ResizableBox.test.tsx mock handle prop cast to any.
Flow Cleanup
.flowconfig, flow-typed/npm/jest_v26.x.x.js
Removes .flowconfig with Flow version, ignored paths, libs, and compiler options. Deletes Flow-typed Jest v26 type definitions (mocks, matchers, lifecycle hooks, test declarations, expect/jest/jasmine globals).

🎯 4 (Complex) | ⏱️ ~60 minutes

🐰 From Flow to TypeScript, a hop so grand,
Types now precise, in TypeScript land,
Babel transpiles, declarations bloom,
Dimensions refactored, no more room,
Build and test dance in harmony.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: convert library from Flow to TypeScript' accurately and concisely summarizes the primary change: a complete migration of the codebase from Flow to TypeScript, which is the core focus across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-05-typescript-conversion

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Migrate lib/ and __tests__/ from Flow to TypeScript:
- Replace @babel/preset-flow with @babel/preset-typescript
- Convert lib/*.js (Flow) to *.ts/*.tsx with explicit types
- Add lib/index.ts as a typed entry-point for declaration emit
- Drop flow-bin, flow-typed/, .flowconfig
- Add tsconfig.json (typecheck), tsconfig.build.json (.d.ts emit), tsconfig.test.json
- build.sh now runs babel + tsc --emitDeclarationOnly
- ESLint switched to @typescript-eslint/parser for ts/tsx
- Tests renamed to .test.tsx / .test.ts, kept JS-style; jest picks them up via babel
- package.json gains 'typecheck' script and 'types' field

Public runtime API is unchanged. PropTypes runtime validation preserved.

Verified: yarn typecheck, yarn lint, yarn test (50 passing), yarn build (emits .js + .d.ts).
@STRML STRML force-pushed the 2026-05-typescript-conversion branch from f373c31 to 9c19c68 Compare May 11, 2026 21:49
@github-actions
Copy link
Copy Markdown

Packj audit found 1/1 risky dependencies.

Click here for details

Registry Package Version Risks
npm react-draggable 4.5.0

undesirable

. Click for details
  • invalid or no author email: no email
  • Triggered by workflow run 27 on commit b1e886c7352b9199ee412cd85057628ef239681a

    Copy link
    Copy Markdown

    @coderabbitai coderabbitai Bot left a comment

    Choose a reason for hiding this comment

    The reason will be displayed to describe this comment to others. Learn more.

    🧹 Nitpick comments (2)
    lib/propTypes.ts (1)

    98-105: 💤 Low value

    Consider simplifying the validator signature.

    The explicit tuple type [Record<string, any>, string, string, any, any, any] matches PropTypes' custom validator signature but is brittle. Consider using ...args: any[] for better maintainability while preserving the same runtime behavior.

    ♻️ Simpler signature
    -  height: (...args: [Record<string, any>, string, string, any, any, any]) => {
    +  height: (...args: any[]) => {
         const [props] = args;
    🤖 Prompt for AI Agents
    Verify each finding against current code. Fix only still-valid issues, skip the
    rest with a brief reason, keep changes minimal, and validate.
    
    In `@lib/propTypes.ts` around lines 98 - 105, The height prop-type validator in
    lib/propTypes.ts uses a brittle explicit tuple type for its arguments; change
    the parameter signature from (...args: [Record<string, any>, string, string,
    any, any, any]) to a looser (...args: any[]) in the height function so it
    remains compatible with PropTypes custom validators but is easier to maintain;
    keep the internal logic that extracts const [props] = args and the conditional
    return of (PropTypes.number.isRequired as any)(...args) versus (PropTypes.number
    as any)(...args) so runtime behavior is unchanged.
    
    lib/ResizableBox.tsx (1)

    82-94: ⚖️ Poor tradeoff

    Type assertions work around React's defaultProps limitation.

    The seven as any casts are necessary because TypeScript doesn't understand that Resizable.defaultProps will provide values for these props. This is a known limitation of TypeScript's support for React's defaultProps pattern.

    For better type safety, consider restructuring the type definitions to make DefaultProps fields explicitly optional in the Props type, or use a more sophisticated pattern like:

    type PropsWithDefaults<T, D> = Partial<D> & Omit<T, keyof D>;

    However, this requires significant refactoring and the current approach is pragmatic given React's defaultProps semantics.

    🤖 Prompt for AI Agents
    Verify each finding against current code. Fix only still-valid issues, skip the
    rest with a brief reason, keep changes minimal, and validate.
    
    In `@lib/ResizableBox.tsx` around lines 82 - 94, The seven "as any" casts on props
    like axis, draggableOpts, handleSize, lockAspectRatio, maxConstraints,
    minConstraints, resizeHandles and transformScale are hiding a typing mismatch
    caused by React defaultProps; update the prop types instead of casting:
    introduce a DefaultProps type listing the defaulted fields and change the
    component Props to use a utility type (e.g. PropsWithDefaults<T,D> = Partial<D>
    & Omit<T, keyof D>) or make those fields optional on Props, then update the
    Resizable/ResizableBox component signature to use that new Props type so the JSX
    props (axis, draggableOpts, handleSize, lockAspectRatio, maxConstraints,
    minConstraints, resizeHandles, transformScale) no longer need "as any" casts and
    onResize (this.onResize) keeps its correct typed signature.
    
    🤖 Prompt for all review comments with AI agents
    Verify each finding against current code. Fix only still-valid issues, skip the
    rest with a brief reason, keep changes minimal, and validate.
    
    Nitpick comments:
    In `@lib/propTypes.ts`:
    - Around line 98-105: The height prop-type validator in lib/propTypes.ts uses a
    brittle explicit tuple type for its arguments; change the parameter signature
    from (...args: [Record<string, any>, string, string, any, any, any]) to a looser
    (...args: any[]) in the height function so it remains compatible with PropTypes
    custom validators but is easier to maintain; keep the internal logic that
    extracts const [props] = args and the conditional return of
    (PropTypes.number.isRequired as any)(...args) versus (PropTypes.number as
    any)(...args) so runtime behavior is unchanged.
    
    In `@lib/ResizableBox.tsx`:
    - Around line 82-94: The seven "as any" casts on props like axis, draggableOpts,
    handleSize, lockAspectRatio, maxConstraints, minConstraints, resizeHandles and
    transformScale are hiding a typing mismatch caused by React defaultProps; update
    the prop types instead of casting: introduce a DefaultProps type listing the
    defaulted fields and change the component Props to use a utility type (e.g.
    PropsWithDefaults<T,D> = Partial<D> & Omit<T, keyof D>) or make those fields
    optional on Props, then update the Resizable/ResizableBox component signature to
    use that new Props type so the JSX props (axis, draggableOpts, handleSize,
    lockAspectRatio, maxConstraints, minConstraints, resizeHandles, transformScale)
    no longer need "as any" casts and onResize (this.onResize) keeps its correct
    typed signature.
    

    ℹ️ Review info
    ⚙️ Run configuration

    Configuration used: defaults

    Review profile: CHILL

    Plan: Pro

    Run ID: cab75a42-e401-45be-859a-7530d33466c4

    📥 Commits

    Reviewing files that changed from the base of the PR and between db2e37e and f373c31.

    ⛔ Files ignored due to path filters (3)
    • __tests__/__snapshots__/Resizable.test.tsx.snap is excluded by !**/*.snap
    • __tests__/__snapshots__/ResizableBox.test.tsx.snap is excluded by !**/*.snap
    • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
    📒 Files selected for processing (21)
    • .babelrc
    • .claude/commands/goal.md
    • .flowconfig
    • __tests__/Resizable.test.tsx
    • __tests__/ResizableBox.test.tsx
    • __tests__/ssr.test.ts
    • build.sh
    • eslint.config.js
    • flow-typed/npm/jest_v26.x.x.js
    • jest.config.js
    • lib/Resizable.tsx
    • lib/ResizableBox.tsx
    • lib/index.ts
    • lib/propTypes.ts
    • lib/utils.js
    • lib/utils.ts
    • package.json
    • tsconfig.build.json
    • tsconfig.json
    • tsconfig.test.json
    • webpack.config.js
    💤 Files with no reviewable changes (3)
    • lib/utils.js
    • .flowconfig
    • flow-typed/npm/jest_v26.x.x.js

    @STRML STRML merged commit 9c19c68 into master May 12, 2026
    4 checks passed
    @STRML STRML deleted the 2026-05-typescript-conversion branch May 12, 2026 15:09
    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