JS to TS in four moves
Because every JavaScript file is nearly valid TypeScript, migration is incremental:
- Rename
file.jstofile.ts. It mostly compiles as is - Annotate parameters, the compiler flags each implicit
anyfor you under strict mode - Extract interfaces for the object shapes flowing through the code, like Unit 3
- Chase the remaining errors, most are real latent bugs being surfaced
Here is step 3 in action. The JavaScript version passed bare objects around, the TypeScript version names the shape:
interface Item { name: string; qty: number; } function receipt(items: Item[]): string
Teams migrate large codebases file by file this way, TypeScript and JavaScript coexist in one project while it happens.
A migrated function, fully typed
This is step 3 of the migration finished: the shape has a name and both the parameter and return type are annotated.
interface Item { name: string; qty: number; } function receipt(items: Item[]): string { const lines: string[] = []; for (const item of items) { lines.push(item.name + " x" + item.qty); } return lines.join(", "); } console.log(receipt([{ name: "pen", qty: 2 }, { name: "pad", qty: 1 }]));
Output
pen x2, pad x1
Why migration can be gradual
- Delete the
Iteminterface and both annotations and the program still runs identically. Types are erased at compile time (lesson 1-1), so removing them changes checking, never behavior. - That property is what lets a team migrate one file at a time. A half-typed codebase is a working codebase.
- The annotations that remain are doing real work. Passing
{ name: "pen" }with noqtyis now an error, and so is readingitem.quantity.
Annotating an untyped function
totalWithShipping already worked as JavaScript. Migration means annotating both parameters and the return type, leaving the body and the output untouched.
function totalWithShipping(prices: number[], shipping: number): number { let sum = 0; for (const p of prices) { sum += p; } return sum + shipping; } console.log(totalWithShipping([10, 20], 5)); console.log(totalWithShipping([3], 2));
Output
35 5
What changed and what did not
- Only the first line changes. Both parameters and the return type gain annotations, and every other line is the original JavaScript.
pricesholds numbers, so its type isnumber[]as in lesson 2-1.- The annotations rule out the accident this function was open to before, where a caller passing
["10", "20"]would have concatenated strings and returned"1020" + 5.
What 30 errors after a rename actually are
They are mostly implicit-any parameters and latent shape bugs the compiler is surfacing, and the right response is to fix them incrementally.
TypeScript parses JavaScript syntax without complaint, so the errors are not syntax problems. They come from the checker demanding parameter types and flagging inconsistent object shapes, and each fix either documents or repairs something that was silently risky before.
Two reassurances are worth holding onto. These are compile-time messages, not crashes, so the program you had yesterday still runs. And the count going down is real progress rather than busywork, because every annotation you add makes the next file easier to migrate.