Migrate JavaScript code to strict TypeScript without breaking it
Convert a JavaScript file or module to TypeScript with types inferred from real usage, a recommended tsconfig, a list of bugs the types reveal and a plan for the rest of the codebase. Designed for ChatGPT, Claude, Gemini and Microsoft Copilot. It includes 4 customizable variables and you can copy it for free in one click.
Intermediate · Code · Pending editorial review
Prompt
Act as a senior TypeScript engineer who has migrated large JavaScript codebases incrementally.
Context:
- Code to migrate: {{js_code}}
- Project and build tooling: {{project}}
- Strictness level: {{strictness}}
- Runtime: {{runtime}}
If the code imports modules I have not shown or receives data whose shape is unclear, ask me before inventing types.
Deliverables:
1. A recommended tsconfig.json for {{strictness}}, explaining the key options (strict, noUncheckedIndexedAccess, allowJs, checkJs, module and moduleResolution for the build setup).
2. The code converted to TypeScript, with types and interfaces inferred from real usage. Mark every type you had to guess with a `// ASSUMPTION:` comment.
3. External data (API responses, localStorage, JSON) typed as `unknown` and validated or narrowed before use.
4. A list of bugs or questionable behavior the types revealed (possible undefined, comparisons across types, mishandled optional arguments), with the line and the proposed fix, kept separate from the conversion.
5. Required @types packages and changes to package.json scripts or ESLint config.
6. A plan to migrate the rest of the project: file order (leaves first, then the root), how to coexist with JS during the transition and how to keep `any` from creeping back.
Constraints:
- Preserve behavior exactly; do not refactor logic in the same step.
- No `any`, `as any`, `@ts-ignore` or non-null assertions `!` without a written justification.
- If a fix changes behavior, propose it separately and do not apply it.
- Use [FILL IN] for anything that cannot be inferred.
Output format: tsconfig, converted code, list of findings and plan, each in its own section.How to use it
- Start with a small file with few dependencies and paste it in full. 2. Say which bundler or framework you use and the strictness you want. 3. Review the ASSUMPTION comments, run tsc --noEmit and your tests, and repeat file by file.
Usage example
Code: utils/cart.js with total and sales tax calculations · Project: React with Vite and ESLint · Strictness: gradual · Runtime: browser.
Sample output
tsconfig.json (key options)
"strict": true, "allowJs": true, "checkJs": true, "noUncheckedIndexedAccess": true and "moduleResolution": "bundler" (matches Vite). The remaining JS gets type-checked while you migrate file by file.
utils/cart.ts
// ASSUMPTION: shape inferred from usage in the original file
export interface CartItem {
readonly id: string;
price: number;
quantity: number;
}
export function cartTotal(items: readonly CartItem[], discountPct = 0): number {
const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
return subtotal * (1 - discountPct / 100);
}
export function loadCart(): CartItem[] {
const raw: unknown = JSON.parse(localStorage.getItem('cart') ?? '[]');
return Array.isArray(raw) ? raw.filter(isCartItem) : [];
}
function isCartItem(value: unknown): value is CartItem {
if (typeof value !== 'object' || value === null) return false;
const v = value as Record<string, unknown>;
return typeof v.id === 'string' && typeof v.price === 'number' && typeof v.quantity === 'number';
}
Findings (not applied)
| Line | Issue | Proposal |
|---|---|---|
| [FILL IN] | JSON.parse throws if the stored value is corrupted | Wrap in try/catch and return [] |
| [FILL IN] | discount sometimes arrived as a string from the form | Convert with Number() at the boundary |
…
Key facts
- Category
- Programming & development · TypeScript
- Output type
- Code
- Level
- Intermediate
- Designed for
- ChatGPT, Claude, Gemini and Microsoft Copilot
- Verified in
- Pending editorial verification
- Variables
- JavaScript code, Project and build, Strictness level and Runtime
- Language
- English
- Price
- Free, no sign-up
- Updated
- Nov 7, 2026
Frequently asked questions
Should I migrate everything at once or gradually?
Gradually, in almost every project. With allowJs you can convert file by file, starting with files that have no dependencies, and turn on strict options once most of the code is typed.
Why use unknown instead of any for external data?
Because unknown forces you to check the data’s shape before using it, while any turns checking off. For API responses, runtime validation with a library like Zod is a good idea.
Can the migration change how my code behaves?
It should not. The prompt keeps the conversion separate from the bugs the types reveal, so you decide what to fix and test it on its own.
What is this prompt for?
Convert a JavaScript file or module to TypeScript with types inferred from real usage, a recommended tsconfig, a list of bugs the types reveal and a plan for the rest of the codebase.
Which AI tools does it work with?
It is designed for ChatGPT, Claude, Gemini and Microsoft Copilot. We have not verified it in these tools yet, so results may vary between them.
How do I customize the prompt?
Click “Customize” and fill in the variables (JavaScript code, Project and build, Strictness level and Runtime). The text updates instantly and you can then copy it in one click. Values are stored only in your browser.
Do I need experience to use it?
It is intermediate: it helps to know the topic so you can provide good context and review the result critically.
Is this prompt free?
Yes. Every HomeCasa Prompts prompt is free, with no sign-up or subscription. You can also use them in professional projects.
Can I trust the AI output?
Treat it as a high-quality draft: always check data, figures and important claims before publishing or making decisions.