Write a JavaScript to TypeScript Migration Prompt That Infers Real Types
Build a JavaScript to TypeScript migration prompt that infers types from call sites, ranks files by any-risk, and locks a per-file output contract.
The fastest way to ruin a JavaScript to TypeScript migration is to let the model type everything as any. It compiles, the PR is green, and you've gained nothing but a false sense of safety. A real JavaScript to TypeScript migration prompt does the opposite: it infers types from how each function is actually called, refuses any unless it's justified, and converts file by file in risk order.
Most guides online lean on a tool. Grit, ts-migrate, Cline with one model. They work, but they're tied to one stack and one workflow, and none of them tells you which files to convert first or where the model quietly gave up.
A prompt fixes the part the tools skip: the judgment.
Why a blind .js-to-.ts rename buys you nothing
Rename a file to .ts, add any wherever the compiler complains, and you've technically migrated. You've also thrown away the entire point of TypeScript. The types that matter, the ones that catch the bug before runtime, come from inference, and inference needs context the model has to be forced to gather.
The stance here is simple. A migration that adds any to silence errors is worse than no migration, because now the code looks typed and isn't. Every any is a hole the type checker can't see through. A good prompt treats any as a failure to infer, not a valid output, and makes the model show its work.
What a JavaScript to TypeScript migration prompt does
A JavaScript to TypeScript migration prompt is a per-file type inferrer that reads a module plus its call sites, infers concrete types, ranks files by conversion risk, and emits typed code against a contract that forbids unjustified any. It works in slices so types propagate outward cleanly.
Run it to:
- Rank files by
any-risk and dependency order so leaves convert first - Infer parameter and return types from real call sites, not guesses
- Forbid
anyin the contract unless the model justifies each one - Add shared interfaces once and reuse them across converted files
- Flag dynamic, runtime-shaped objects that need a manual type
- Keep
allowJson so JS and TS coexist mid-migration
The risk ranking is what keeps a thousand-file migration from collapsing into a wall of cascading errors.
Anatomy of the prompt
Variables
{{js_source}} → the JavaScript file(s) to convert
{{call_sites}} → how the module is used elsewhere (for inference)
{{ts_config}} → strictness flags in play (strict, noImplicitAny)
{{shared_types}} → optional: existing interfaces to reuse
Prompt
Role: you are a JavaScript-to-TypeScript migration engineer.
Task: convert {{js_source}} under {{ts_config}}.
Rules:
- Infer types from {{call_sites}}; never default to any.
- Each any must carry a one-line justification or it's rejected.
- Flag runtime-shaped objects for a manual type decision.
Output contract
Return: typed file + the any-justification list + risk notes.
1. Set the strictness up front
Put strict and noImplicitAny in {{ts_config}}. The model types more carefully when it knows the compiler will reject loose types, the same way you'd write differently knowing the linter's on.
2. Feed the call sites
Inference is only as good as the context. Paste how the module gets used into {{call_sites}} so the model types a parameter from its real arguments, not from a hopeful guess.
3. Read the any-justification list
Every any the model emits comes with a reason. That list is your review queue, the spots where the code is too dynamic to type cleanly and you need to decide.
The difference between a real migration and a cosmetic one is how you handle any. Let it slip in silently and you've shipped untyped code wearing a TypeScript badge. Force the model to justify each any in the contract, and the migration surfaces exactly where the types are genuinely hard. Those spots are where a human should look, not where the model should bluff.
Prompt-craft patterns for type migration
Infer from usage, not from the definition alone. A function's parameter types live in how it's called. A prompt that only reads the function body guesses; one that reads {{call_sites}} infers. Force the call-site pass.
Ban any by contract. Don't ask politely. Make the output contract reject any unless it carries a justification. Otherwise the model takes the easy path on every ambiguous parameter.
Convert leaves before roots. A shared module typed last means every file that imports it gets re-checked. Rank by dependency order so types flow outward and each conversion stays local.
Where Claude and GPT-4o diverge on strictness
The two models treat strict differently. Claude tends to honor a strict: true instruction and infer narrower types, often introducing a union or a generic where GPT-4o would reach for any. GPT-4o produces clean code fast but defaults to loose types unless the no-any rule sits on the final line of the prompt, where recent-token weighting keeps it in attention.
Both models struggle with the same thing: objects whose shape is decided at runtime. A config parsed from JSON, a payload that varies by branch. Neither should invent a type there, so the contract routes those to the manual-review list. OpenAI's own guidance notes that loosely specified outputs drift; restate the strictness contract for GPT-4o, and pin the model version, because a converter that started accepting any more freely after an update is a regression hiding behind a green build.
How this fits a larger migration
Typing a codebase is often one phase of a bigger upgrade. The staging logic, convert in reversible slices, mirrors any framework move. For the broader pattern, the framework migration prompt covers staged rollout, and if you're also changing the language's idioms rather than just adding types, the cross-language refactor prompt handles that case.
Variables you'll set
| Variable | Required | What it is |
|---|---|---|
{{js_source}} | Yes | The JavaScript file or files to convert |
{{call_sites}} | Recommended | How the module is used elsewhere |
{{ts_config}} | Yes | Strictness flags in play |
{{shared_types}} | Optional | Existing interfaces to reuse |
Getting started
- Copy the structure into ChatGPT, Claude, or Gemini.
- Set
{{ts_config}}with your real strictness flags. - Paste the module and its
{{call_sites}}so inference has context. - Run it and read the any-justification list before the code.
- Resolve each justified
anyby hand or accept it deliberately. - Convert leaf files first, then work inward as shared types settle.
For a migration spanning hundreds of files with risk ranking and staging already wired in, the Framework Migration Harness Playbook runs the full sequence.
Browse the migration prompt packs →The Framework Migration Harness Playbook does this end-to-end: a {{source_framework}} and {{target_framework}} pair feeds a staged plan where each file ships and verifies independently, so a JS-to-TypeScript pass converts leaves first and propagates shared types outward instead of landing a thousand anys in one PR. It's part of The Complete AI Prompts Bundle, a one-time lifetime license to the whole catalog plus future packs, worth it if you run more than one migration a year.
Once files are typed, the next job is confirming the typed code behaves like the JavaScript it replaced. The Cross-Language Refactor Harness locks a per-file output contract for that behavior check. New to buying packs versus assembling your own? Start with how to choose a reusable AI prompt pack.
See the Cross-Language Refactor Harness →Common questions
Won't the model just type everything as any?
How do you migrate a large JS codebase without breaking everything?
Does Claude or GPT-4o follow strict mode better?
Get the prompt packs this guide is built on
Ready-to-paste prompts with documented variables and usage guides for ChatGPT, Claude, and Gemini. One-time payment, own it forever.
More prompt guides

A Discovery Call Synthesis Prompt That Grades the Evidence, Not the Vibes
Sales and product teams run dozens of discovery calls a quarter, then synthesize them from memory the night before the roadmap meeting. The loud interview wins. A vivid quote from one account becomes…

A Sales Meeting Follow-Up Prompt That Recaps, Updates the CRM, and Drafts the Email
Ask any rep what happens after a good sales call, and the honest answer is: four tools and twenty minutes. Notes get retyped into a recap. The recap gets mined for action items. Someone updates the Sa…

Agent Prompt vs System Prompt: What Each One Controls
The terms get used interchangeably, and that's where agents go wrong. Agent prompt vs system prompt isn't a style preference. It's the difference between the rules that hold on every single call and t…