Learn TypeScript - Migrating JavaScript Code to TypeScript
Episode 13 of 23

Learn TypeScript - Migrating JavaScript Code to TypeScript

This episode covers the strategy for migrating an existing JavaScript codebase to TypeScript gradually: allowJs, checkJs, JSDoc annotations, controlled use of any, and converting files one by one until strict mode is active.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

It's tempting to rewrite a JavaScript codebase from scratch. In practice, that's expensive and risky. A realistic migration runs gradually: TypeScript is adopted while the application keeps working every day. Episode 13 covers how to do it.

The key is mixed mode. TypeScript can process JavaScript and TypeScript files in one project, typing the files already converted while still accepting those that aren't. Type guarantees are raised step by step, not in a leap.

You'll learn to enable allowJs and checkJs, start checking with JSDoc, use any as a temporary bridge, then convert files and tighten options until strict mode is active.

The Gradual Strategy with allowJs

The conversion starts in the tsconfig settings. The allowJs option makes the compiler accept JavaScript files:

Aktifkan allowJs
{
    "compilerOptions": {
        "allowJs": true,
        "checkJs": false,
        "outDir": "dist"
    }
}

With allowJs: true, .js files are copied and processed along the way, so you can add .ts files in the middle of an old project without waiting for everything to finish. Compilation keeps running, the app keeps being deployed, and the migration proceeds without halting development.

checkJs and Control Comments

Once stable, enable checking on JavaScript files:

Aktifkan checkJs
{
    "compilerOptions": {
        "allowJs": true,
        "checkJs": true
    }
}

With checkJs: true, the compiler starts checking .js files and reports type errors it can detect from the shape of the code. For files not yet ready to be checked, insert a control comment at the top of the file:

JSNonaktifkan pemeriksaan per file
// @ts-nocheck
 
function hitung(a, b) {
    return a + b;
}

The // @ts-nocheck comment disables checking for one specific file. Conversely, // @ts-check enables checking on .js files where checking is globally off. Both comments give per-file control during the transition.

JSDoc as a Starting Point

Before changing extensions, you can type functions with JSDoc:

JSTipe lewat JSDoc
/**
 * Menjumlahkan dua angka.
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
function tambah(a, b) {
    return a + b;
}

The @param {number} and @returns {number} declarations add types without changing the file extension. JSDoc takes advantage of checkJs, delivers safety early, and becomes documentation that can be moved automatically when the file is converted.

Controlled Use of any

Not all code can be accurately typed right away. any is a legitimate bridge during migration:

Any sebagai jembatan
function prosesData(data: any): any {
    return data.peta?.map((item: any) => item.nilai);
}

The declaration data: any postpones detailed typing until the data structure is understood. The key is control: any only in the file being handled, marked with a comment so it isn't forgotten, and reduced gradually. Temporary any is far better than stopping completely.

Temukan sisa any
rg "\bany\b" src --glob "*.ts"

The rg \bany\b command above finds every use of the any keyword in the source. This list becomes a checklist for reducing any until the project is ready for strict mode.

Gradual Conversion and Tightening

The next step changes file extensions one at a time, starting from the smallest and most isolated files:

Ubah ekstensi dan compile
git mv src/utils/hitung.js src/utils/hitung.ts
npx tsc --noEmit

The git mv command changes the extension while preserving git history, then npx tsc --noEmit verifies the result. The conversion starts with pure utilities that have no dependencies, moves up to the modules that use those utilities, and finally reaches the top-level components.

Tip

During migration, enable only one strict option at a time. strictNullChecks first, then the others. Small, frequent changes are easier to track than a big overhaul that stalls the whole project.

Closing

Episode 13 shows that migrating to TypeScript doesn't have to stop production. With allowJs, checkJs, JSDoc, controlled any, and gradual conversion, an old codebase can be secured while continuing to run normally.

Key takeaways:

  • allowJs lets the compiler process JavaScript and TypeScript files together.
  • // @ts-nocheck and // @ts-check control checking per file.
  • JSDoc adds types to .js files without changing the extension.
  • Controlled any bridges files that haven't been converted yet.
  • Conversion starts with small, isolated files.
  • Strict options are tightened one at a time.

In the next episode 14 we'll discuss type declarations for external libraries — using @types packages, writing ambient declarations, and understanding module resolution.

Learn TypeScript - Migrating JavaScript Code to TypeScript | Learn TypeScript