React Next.js Radar

Practical, step-by-step TS migration for legacy React apps

Practical, step-by-step TS migration for legacy React apps

Migrating React to TypeScript

Key Questions

How do I start migrating without breaking the app?

Enable TypeScript side-by-side with JavaScript by setting allowJs: true in tsconfig and keeping noEmit: true initially. Rename one component or module at a time to .ts/.tsx, fix the type errors incrementally, and use any or // @ts-ignore temporarily to unblock critical paths.

When is it OK to use any or // @ts-ignore?

Use any and // @ts-ignore sparingly as short-term measures to keep development moving — for example when dealing with complex legacy code or untyped third-party libraries. Track and prioritize replacing them with precise types during regular refactoring cycles.

What tooling changes should I consider during migration?

Add ESLint with @typescript-eslint for consistent linting, Prettier for formatting, and type-aware editor plugins. Consider adopting modern dev tooling (e.g., Vite 8 / Rolldown) to speed up builds and get faster type-check feedback, but only after verifying compatibility with your project.

How should I handle third-party libraries without TypeScript types?

First look for community @types packages. If none exist, add minimal ambient declarations (.d.ts) for the parts you use, or wrap the library in a thin typed adapter. Reserve // @ts-ignore as a last resort and plan to replace it with proper typings.

What are good early wins to build momentum?

Start by typing common utility functions, small stateless components, and shared hooks. Add interfaces for frequently used props/state shapes and enforce them in reviews. These quick wins improve DX and make larger refactors safer.

Modernizing Legacy React Apps: Step-by-Step TS Migration and the Rise of Rust-Powered Toolchains

Migrating a long-standing React codebase from vanilla JavaScript to TypeScript is a transformative journey that significantly enhances code safety, developer experience, and future scalability. Over recent years, the tooling landscape has evolved rapidly, with new bundlers and build tools emerging that promise faster feedback loops and streamlined workflows. Recent developments, such as the advent of Rust-based bundlers like Rolldown and Oxc, are reshaping the JavaScript toolchain landscape, offering exciting prospects for developers undertaking such migrations.

The Pragmatic Approach to TypeScript Migration in Legacy React Apps

Step 1: Setting Up for Incremental Migration

The foundation begins with integrating TypeScript into your project:

  • Install TypeScript and React typings:

    npm install --save-dev typescript @types/react @types/react-dom
    
  • Configure tsconfig.json for flexibility:

    A crucial aspect is to allow mixed JavaScript and TypeScript files, enabling gradual migration:

    {
      "compilerOptions": {
        "target": "ES6",
        "module": "ESNext",
        "jsx": "react-jsx",
        "strict": true,
        "noEmit": true,
        "allowJs": true,
        "skipLibCheck": true
      },
      "include": ["src"]
    }
    

This setup permits existing JavaScript files to coexist with TypeScript, avoiding the daunting prospect of rewriting everything upfront.

Step 2: Incremental File and Codebase Migration

Rather than a big-bang rewrite, adopt a phased approach:

  • Rename files gradually: Change .js files to .tsx (for React components) or .ts (for utilities). The compiler now analyzes these files.
  • Add types incrementally:
    • Start with simple components, potentially leveraging JSDoc or PropTypes initially.
    • Use any sparingly to unblock progress, then refine to precise types over time.
  • Focus on small, manageable units: Components, hooks, utility modules—target these first for type annotations.

Step 3: Leveraging Tooling and Community Resources

  • Linters and formatters: Integrate ESLint with TypeScript plugins and Prettier to enforce code quality.
  • Community typings: Many libraries now offer official TypeScript definitions, reducing the need for custom typings.
  • Use modern bundlers: Tools like Vite 8, Rolldown, and Oxc are gaining popularity, promising faster build times and enhanced developer feedback.

Step 4: Handling Pitfalls and Common Challenges

Legacy codebases often contain quirks:

  • Refactor complex parts separately: Large components or utility functions may require isolated refactoring.
  • Explicit typing where inference fails: Be proactive in defining types for function parameters, state, and props.
  • Manage third-party libs: For libraries lacking typings, write minimal ambient type declarations or temporarily use @ts-ignore.
  • Use // @ts-ignore sparingly: To bypass issues during migration, but aim to eliminate these as the code improves.

Step 5: The Benefits of a Progressive Migration

Adopting TypeScript yields tangible benefits:

  • Compile-time safety: Catch bugs early before deployment.
  • Enhanced developer experience: Better autocompletion and refactoring support.
  • Easier onboarding: Clear contracts for components and APIs improve team ramp-up.
  • Future-proofing: Simplifies adding features and refactoring in the long run.

The Rise of Rust-Powered JavaScript Toolchains: Vite 8, Rolldown, and Oxc

While TypeScript migration focuses on code quality, the underlying build tools significantly influence developer productivity. Recently, the JavaScript ecosystem has seen a notable shift toward Rust-based bundlers, exemplified by Vite 8 and its new runtime components.

Vite 8 and the Rust Ecosystem

Vite 8, currently in beta, runs on Rolldown, a bundler built with Rust that replaces traditional tools like esbuild and Rollup under the hood. This transition is more than just a backend change; it represents a move toward:

  • Faster build times
  • More reliable incremental builds
  • Better performance on large projects
  • Enhanced developer feedback with rapid hot module replacement (HMR)

Why Rust?

Rust's emphasis on safety and performance translates into:

  • Efficient memory management
  • Parallel execution capabilities
  • Reduced runtime errors

This allows bundlers like Rolldown and Oxc to process large codebases swiftly, providing immediate feedback critical during extensive migrations.

Implications for Developers

For teams undertaking legacy React migrations:

  • Faster iteration cycles mean less downtime and quicker iterations.
  • Reduced build times facilitate more frequent testing and refactoring.
  • Potential for improved tooling stability and fewer bugs in the build pipeline.

Current Status and Future Outlook

The convergence of incremental TypeScript adoption and Rust-powered bundlers signifies a maturation of the modern JavaScript ecosystem, especially for long-standing projects.

  • Developers can now gradually transform their React codebases for better safety and maintainability without sacrificing productivity.
  • The new tooling landscape promises faster builds, more reliable feedback, and a smoother migration path.

In conclusion, migrating a legacy React app to TypeScript is more achievable than ever—especially with a pragmatic, incremental approach combined with cutting-edge tools. Embracing both the code modernization strategies and the powerful, Rust-based build ecosystems will position your projects for sustained success in a rapidly evolving development environment.


Remember: Patience, incremental progress, and leveraging the latest tooling innovations are your best allies in this transformation journey.

Sources (2)
Updated Mar 18, 2026
How do I start migrating without breaking the app? - React Next.js Radar | NBot | nbot.ai