AceDevHub
Production TypeScriptFree

Migrating JavaScript to TypeScript

Gradual migration strategies — allowJs, JSDoc, rename patterns, typing third-party modules, and when to reach for any vs proper types.

AdvancedFreeMigration

Few teams rewrite overnight. Gradual migration keeps shipping while types expand coverage. TypeScript supports allowJs and checkJs so .js and .ts coexist — rename files incrementally, add types at module boundaries first, and tighten strict flags as debt clears.

Migration order that works: enable allowJs, turn on noImplicitAny for new .ts files only via separate tsconfig, type shared utilities and API contracts, then leaf modules. Fight the urge to any-stub everything — unknown plus narrowing or Zod at boundaries beats permanent any debt.

allowJs and checkJs

allowJs includes JavaScript files in the project. checkJs typechecks .js files using JSDoc annotations — useful before renaming. maxNodeModuleJs optionally checks .js in node_modules — usually leave false.

tsconfig-migration.json
Loading editor…

JSDoc as a stepping stone

@param and @returns in JSDoc give .js files types without renaming. @typedef defines object shapes. When ready, rename to .ts and convert JSDoc to native syntax — types transfer directly.

utils.js
Loading editor…

Renaming .js to .ts incrementally

Start with leaf modules with no dependents — pure utilities, formatters, constants. Then move up to services consumed by few callers. Leave complex legacy modules for last when typing dependencies exist. Each rename surfaces errors at import sites — fix callers as the graph tightens.

migration-steps.ts
Loading editor…

Ambient declarations and @types

DefinitelyTyped packages (@types/lodash) provide community .d.ts for popular libraries. For internal untyped JS, write minimal declaration files — declare module with only the exports you use. Avoid empty declare module unless temporarily stubbing.

legacy-lib.d.ts
Loading editor…
StrategyWhen
allowJsMixed codebase
JSDocDelay rename
Rename leaf-firstLow dependency files
@types/*Popular npm packages

When to use any during migration

any is acceptable as a temporary bridge with a TODO and ticket — not as a permanent escape. Prefer unknown at boundaries and narrow. @ts-expect-error documents intentional suppressions with expiry. Track any count in CI and ratchet down over sprints.

  • allowJs for coexistence
  • JSDoc before rename
  • Type shared modules first
  • Ratchet any count down

  1. 1allowJs + checkJs for gradual entry
  2. 2JSDoc types .js before rename
  3. 3Migrate leaves then shared core
  4. 4Enable strict when any debt is low
  5. 5Course complete — apply types in production