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.