placeholder

How to Migrate Your Node.js/Express App from JavaScript to TypeScript

10 Mar 2025

Ernesto Ballon

Ernesto Ballon

5 min read

Migrating your Node.js/Express application from JavaScript to TypeScript enhances maintainability, scalability, and type safety. This guide provides a structured approach to smoothly transition your project.


Setup Checklist

Before diving into the migration, ensure you complete these essential setup steps:

✅ Install TypeScript and type definitions

✅ Create a tsconfig.json file

✅ Update package.json scripts

✅ Define custom type definitions


Step-by-Step Migration Guide

1. Rename Files

Rename your JavaScript files to TypeScript files by changing the extensions from .js to .ts:

src/server.js → src/server.ts
scripts/deploy.js → scripts/deploy.ts

For files that include JSX, use the .tsx extension.


2. Update Import Statements

TypeScript requires explicit file extensions when using ES module imports:

// Before
import User from '../models/User';

// After
import User from '../models/User.js';

Although your TypeScript files end in .ts, compiled JavaScript files will have .js, so ensure imports reflect this.


3. Add Type Annotations

Explicitly defining types improves code reliability:

// Before
function getUserById(id) {
  // ...
}

// After
function getUserById(id: string): Promise<User | null> {
  // ...
}

4. Handle Environment Variables

Secure your environment variables using TypeScript:

// src/config/env.ts
import dotenv from 'dotenv';
import { EnvVariables } from '../types/index.js';

dotenv.config();

export const env: EnvVariables = {
  MONGO_URI: process.env.MONGO_URI || 'mongodb://localhost:27017/your_database',
  PORT: process.env.PORT || '3000',
  CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
  // Add other environment variables
};

5. Type Middleware Functions

For custom middleware, define explicit types:

// src/middleware/auth.ts
import { Request, Response, NextFunction } from 'express';
import { AuthenticatedRequest } from '../types/index.js';

export const authMiddleware = (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  const authenticatedReq = req as AuthenticatedRequest;
  // ... authentication logic
  next();
};

6. Type Models and Schemas

Enhance your Mongoose models with TypeScript for better data consistency.

// Example in src/models/exampleModel.ts

7. Update Build and Run Scripts

Modify your package.json scripts to support TypeScript:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/server.js",
    "dev": "nodemon --exec ts-node src/server.ts"
  }
}

Use these commands:

  • npm run build – Compile TypeScript to JavaScript
  • npm start – Run the production server
  • npm run dev – Watch mode with nodemon and ts-node

Common Issues and Solutions

1. “Cannot find module” Errors

Install missing type definitions:

npm install --save-dev @types/[library-name]

2. Type Assertions

Sometimes TypeScript cannot infer the correct type:

const userData = JSON.parse(jsonString) as User;

3. Using any as a Temporary Solution

When unsure about a type, use any but replace it later with precise typing:

let complexData: any = fetchComplexData();

4. Handling Third-Party Libraries Without Types

Create a type declaration file for unsupported libraries:

// src/types/declarations.d.ts
declare module 'module-without-types' {
  export function someFunction(param: string): void;
  export const someValue: number;
}

Next Steps

✅ Continue migrating files incrementally
✅ Integrate TypeScript-based testing
✅ Configure ESLint for TypeScript
✅ Define interfaces for API responses

By following these steps, your Node.js/Express application will be fully migrated to TypeScript, ensuring a more structured, scalable, and maintainable codebase. 🚀