Skip to main content

Migrate JS to TS Walkthrough

Here are the concrete steps to incrementally migrate an existing JavaScript project to TypeScript.

Step 1: Install and Init

First, install the compiler and generate the configuration file.

npm install --save-dev typescript
npx tsc --init

Step 2: Configure for Coexistence

Open the generated tsconfig.json. The critical flag for incremental migration is allowJs.

{
"compilerOptions": {
"target": "es2022",
"moduleResolution": "node",
"strict": true, // Enforce strict rules on all .ts files
"allowJs": true, // VERY IMPORTANT: Allow importing .js files!
"checkJs": false, // Do not typecheck .js files yet
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}

With allowJs: true, your bundler and TS compiler won't crash when a .ts file imports a legacy .js file.

Step 3: Pick a Leaf Node and Rename

Find a utility file with no internal dependencies.

// math.js
export function calculateTotal(price, tax, discount) {
return (price + tax) * (1 - discount);
}

Rename it to math.ts. TypeScript will immediately flag errors because price, tax, and discount implicitly have the type any (which violates strict mode).

Step 4: Fix the Types

Add the explicit types.

// math.ts
export function calculateTotal(price: number, tax: number, discount: number): number {
return (price + tax) * (1 - discount);
}

Now, any other file (even a .js file) that imports calculateTotal will get full IDE autocomplete and type information for this function!

JSDoc as a Stepping Stone

If you cannot rename a file to .ts yet (perhaps due to complex build tooling issues), you can get 80% of TypeScript's benefits directly in JavaScript by using JSDoc comments.

Turn on "checkJs": true in your tsconfig, and write:

/**
* @param {number} price
* @param {number} tax
* @returns {number}
*/
export function calculateTotal(price, tax) { ... }

TypeScript will read these comments and typecheck your JS files as if they were TS!

Rename files one by one starting from the bottom of the dependency tree. Ensure allowJs is true in your config so the newly typed files can seamlessly interact with the legacy JavaScript codebase.