TypeScript Migration from JavaScript

Gradually migrate an existing JavaScript project to TypeScript.


Migration Strategy

  1. Add tsconfig.json
  2. Rename .js to .ts
  3. Gradually Add Type Annotations
  4. Enable Strict Mode

Configure tsconfig.json

tsconfig.json

{
    "compilerOptions": {
        // Initial stage: relaxed configuration
        "target": "ES2020",
        "module": "commonjs",
        "strict": false,
        "noImplicitAny": false,
        "strictNullChecks": false,
        "skipLibCheck": true,

        // Allow JS files
        "allowJs": true,
        "checkJs": false,

        // Output directory
        "outDir": "./dist",
        "rootDir": "./src"
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules", "dist"]
}

Gradually Enable Strict Checks

Enable in Phases

// Phase 1: Basic migration
{
    "compilerOptions": {
        "strict": false,
        "noImplicitAny": false
    }
}

// Phase 2: Enable type checking
{
    "compilerOptions": {
        "strict": true,
        "noImplicitAny": true,
        "strictNullChecks": true
    }
}

// Phase 3: Fully strict
{
    "compilerOptions": {
        "strict": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "strictFunctionTypes": true,
        "strictPropertyInitialization": true
    }
}

JSDoc Type Annotations

Use JSDoc in JavaScript to add types.

utils.js

/**
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */

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

/**
 * @typedef {Object} User
 * @property {number} id
 * @property {string} name
 * @property {string} email
 */


/**
 * @param {number} id
 * @returns {Promise<User>}
 */

function getUser(id) {
    return fetch(`/api/users/${id}`).then(r => r.json());
}

Output:

JSDoc 注释添加成功

Type Declaration Files

Create declarations for modules without type definitions.

src/types/my-module.d.ts

declare module "my-module" {
    export function doSomething(param: string): void;
    export class MyClass {
        constructor(options: { name: string });
        name: string;
    }
}

declare Keyword

Example

// Declare global variable
declare var GLOBAL_CONFIG: {
    apiUrl: string;
    version: string;
};

// Declare global function
declare function myFunction(param: string): void;

// Declare namespace
declare namespace MyNamespace {
    function doSomething(): void;
}

// Usage
console.log(GLOBAL_CONFIG.apiUrl);
myFunction("hello");
MyNamespace.doSomething();

Output:

Declaration successful

Migration Tools

  • tsc --allowJs:Compile JS files
  • checkJs:Check JS types
  • // @ts-check:Single-file type checking
  • // @ts-ignore:Ignore errors

legacy.js

// @ts-check
// @ts-ignore
var result = someLegacyFunction();

Best Practices

  1. Start migration from critical modules
  2. Add unit tests
  3. Gradually enable strict mode
  4. Use JSDoc comments
  5. Create type declaration files

Summary

  • Incremental:Step-by-step migration
  • JSDoc:Type annotations
  • Declaration files:.d.ts
  • Strict mode:Enable in phases

Other extensions