Skip to main content

Module 31: Migration Strategies

Learn strategies for migrating JavaScript projects to TypeScript incrementally and safely.


1. Initial Setup

# Install TypeScript
npm install --save-dev typescript @types/node

# Initialize tsconfig.json
npx tsc --init
// tsconfig.json (Initial migration settings)
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"allowJs": true, // Allow JS files
"checkJs": false, // Don't check JS files initially
"strict": false, // Start lenient
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

2. Gradual Migration Approach

Step 1: Rename Files

# Rename .js to .ts gradually
mv src/utils.js src/utils.ts
mv src/index.js src/index.ts

Step 2: Fix Type Errors

// Before (JavaScript)
function add(a, b) {
return a + b;
}

// After (TypeScript)
function add(a: number, b: number): number {
return a + b;
}

Step 3: Enable Strict Mode Gradually

{
"compilerOptions": {
"strict": false,
"noImplicitAny": true, // Enable first
"strictNullChecks": false // Enable later
}
}

3. Type Definition Installation

# Install type definitions for libraries
npm install --save-dev @types/express
npm install --save-dev @types/lodash
npm install --save-dev @types/react
npm install --save-dev @types/node

4. JSDoc to TypeScript

// Before (JSDoc)
/**
* @param {string} name
* @param {number} age
* @returns {{name: string, age: number}}
*/
function createUser(name, age) {
return { name, age };
}

// After (TypeScript)
interface User {
name: string;
age: number;
}

function createUser(name: string, age: number): User {
return { name, age };
}

5. Handling Third-Party Libraries

// Create custom type definitions
// types/my-library.d.ts
declare module "my-library" {
export function doSomething(value: string): void;
export class MyClass {
constructor(value: number);
method(): string;
}
}

6. Any to Proper Types

// Initial migration (use any temporarily)
let data: any = fetchData();

// Better
interface Data {
id: number;
name: string;
}

let data: Data = fetchData();

// Best (with validation)
const schema = z.object({
id: z.number(),
name: z.string()
});

type Data = z.infer<typeof schema>;
let data: Data = schema.parse(fetchData());

7. Module System Conversion

// CommonJS
const express = require("express");
module.exports = { app };

// ES Modules (TypeScript)
import express from "express";
export { app };

8. Configuration Migration

// config.js (JavaScript)
module.exports = {
port: 3000,
host: "localhost",
database: {
url: "mongodb://localhost"
}
};

// config.ts (TypeScript)
interface Config {
port: number;
host: string;
database: {
url: string;
};
}

const config: Config = {
port: 3000,
host: "localhost",
database: {
url: "mongodb://localhost"
}
};

export default config;

9. Test Migration

// test.js (JavaScript with Jest)
test("adds numbers", () => {
expect(add(2, 3)).toBe(5);
});

// test.ts (TypeScript with Jest)
import { add } from "./math";

test("adds numbers", () => {
expect(add(2, 3)).toBe(5);
});

10. Build Script Updates

// package.json
{
"scripts": {
"build": "tsc",
"build:watch": "tsc --watch",
"dev": "ts-node-dev src/index.ts",
"start": "node dist/index.js"
}
}

11. Migration Checklist

☐ Install TypeScript and @types packages
☐ Create tsconfig.json with lenient settings
☐ Enable allowJs temporarily
☐ Rename .js files to .ts incrementally
☐ Fix type errors file by file
☐ Add type definitions for external libraries
☐ Replace any types with proper types
☐ Enable strict mode gradually
☐ Update build scripts
☐ Migrate tests
☐ Update CI/CD pipeline
☐ Document migration process

12. Common Migration Patterns

Implicit Any Parameters

// Before
function process(data) {
return data.value;
}

// After
interface Data {
value: string;
}

function process(data: Data): string {
return data.value;
}

Null/Undefined Handling

// Before
function getUser(id) {
return users.find(u => u.id === id);
}

// After
function getUser(id: number): User | undefined {
return users.find(u => u.id === id);
}

Key Takeaways

Gradual migration prevents disruption
allowJs enables coexistence
JSDoc helps initial typing
✅ Install @types packages
✅ Enable strict mode incrementally
✅ Replace any with proper types


Practice Exercises

Exercise 1: Migrate Express App

Convert an Express.js application to TypeScript.

Exercise 2: Migrate React App

Convert a React JavaScript app to TypeScript.


Next Steps

In Module 32, we'll explore Advanced Project Configuration for complex TypeScript setups.