Verified migration
JavaScript → TypeScript, verified by the real compiler.
Refactyl converts a JavaScript codebase to TypeScript, runs every file through tsc --noEmit, and repairs until the build is clean, or flags exactly what it couldn't safely touch. You review a verified diff, not a hopeful prompt. Your first migration is free, up to 100 files.
No credit card · Docker-sandboxed · Deleted on handoff · How we handle your code →
Why this migration is hard to get right
any-soup is undetectable
A naive migration can reach zero compiler errors by writing `const x: any` everywhere, silencing tsc instead of typing the code. You only discover the types are a lie when autocomplete stops working and the bugs tsc should have caught sail through code review.
Cross-file inference breaks per-file prompting
TypeScript types flow across modules. A model that converts one file at a time invents the type of a function it imports instead of reading it from the source. The guesses drift, and the errors pile up two files later. A whole-repo batch sees the full import graph.
package.json and tsconfig need exact versions
The wrong @types/* version produces hundreds of spurious errors. A missing DOM lib makes browser globals unknown. Correct versions require a curated lookup, not a guess, and a hallucinated @types package name will fail npm install.
How Refactyl does it
The migration is deterministic up to file classification: Refactyl detects which files to convert (skipping minified code, test directories, and dist/), generates tsconfig.json and @types/* entries from a curated version-aware map, then transforms in batches with cross-file context. The compiler-feedback repair loop runs tsc --noEmit against each file's real errors (up to three rounds) and fixes with real types. `any` and `@ts-ignore` are policy violations, not fixes.
Compiler: tsc --noEmit · Zero files ship unverified.
const express = require('express')
async function getUser(req, res) {
const user = await db.find({ id: req.params.id })
if (!user) return res.status(404).json({ error: 'not found' })
res.json(user)
}
module.exports = { getUser }import { Request, Response } from 'express'
async function getUser(req: Request, res: Response): Promise<void> {
const user = await db.find({ id: req.params.id })
if (!user) { res.status(404).json({ error: 'not found' }); return }
res.json(user)
}
export { getUser }Measured against real alternatives
ts-migrate
0 of 5 repos ran
Crashes on modern Node before converting a single file. 600k downloads/month, abandoned in practice.
Raw LLM (gpt-4.1-mini)
27–40 any/KLOC
Compiles, but by writing any everywhere, silencing the compiler instead of typing the code.
Refactyl
1–8 any/KLOC
Fewer errors AND 3–30× less any on all five repos. Real types, not escape hatches.
5 real OSS repos · pinned commits · compiler-judged · July 2026 · Full benchmark with raw numbers →
Manual / raw LLM vs Refactyl
| Concern | Manual / raw LLM | Refactyl |
|---|---|---|
| Compiler verdict on handoff | You run tsc after reviewing; errors are your problem | tsc passes before you see the diff, or the file is flagged |
| any-density | 20–40 any/KLOC typical for raw-LLM migrations | 1–8 any/KLOC on the public benchmark (same 5 repos) |
| tsconfig + @types generation | Guess the right versions; iterate on spurious errors | Curated version-aware map, no hallucinated package names |
| Cross-file type consistency | Per-file prompting invents types it can't see | Whole-repo batch preserves the full inference graph |
| Files that can't safely convert | Silently broken, or left for you to discover | Flagged with the reason; original preserved unchanged |
| ts-migrate as an alternative | Crashes on modern Node: 0 of 5 repos ran in our benchmark | · |
FAQ
JavaScript → TypeScript migration: common questions
Real questions engineers ask before migrating JavaScript to TypeScript, answered honestly.
Ready to migrate?
Run your JavaScript repo through the real compiler.
One free migration per month, up to 100 files. No credit card. Every file gated by tsc --noEmit, repaired until clean, or clearly flagged with the reason.
No credit card · Docker-sandboxed · Deleted on handoff · Never used for training