Q40 of 40 · JavaScript
How do you lead a JavaScript-to-TypeScript migration for a large automation suite?
Short answer
Short answer: Migrate incrementally: enable `allowJs` + `checkJs` first to catch errors without converting. Prioritise shared utilities (Page Objects, fixtures, helpers) over individual tests. Set a per-sprint conversion quota, enforce `noImplicitAny` in converted files, and block new JS files via lint rules once the team reaches proficiency.
Detail
A large-scale JS→TS migration is an engineering programme, not a weekend task. The goal is to capture TypeScript's benefits without stalling feature work or burning the team.
Phase 1 — Enable without converting (Week 1–2):
- Add
tsconfig.jsonwithallowJs: true,checkJs: true,strict: false - Add
// @ts-checkto the highest-churn files first - Fix type errors surfaced without renaming files — this gives immediate value
Phase 2 — Convert shared code first (Weeks 3–8):
- Rename high-value shared modules: Page Objects, fixture factories, API helpers, custom matchers
- These deliver the most refactoring safety and intellisense benefit per file converted
- Add
// @ts-nocheckas a temporary escape hatch on complex files; remove it per sprint
Phase 3 — Tighten and enforce:
- Ratchet
strict: truefile-by-file as each file is cleaned - Add an ESLint rule (
no-explicit-any, or custom): block regressions on converted files - Add a CI gate:
tsc --noEmitmust pass; new.jsfiles in/teststrigger a warning - Training: pair-program TypeScript-heavy refactors with the team
Metrics: Track % files converted, % type errors remaining, and test suite runtime (TypeScript compilation should not meaningfully slow CI).
// EXAMPLE
// tsconfig.json — phased migration settings
// Phase 1: check without converting
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"strict": false, // loosened to reduce initial noise
"noImplicitAny": false // will tighten per file
}
}
// Phase 2: per-file strictness
// Add to each converted file's jsconfig or use override:
// /* @ts-check */
// // @ts-strict ← per-file strict opt-in
// Phase 3: CI gate
// package.json
{
"scripts": {
"typecheck": "tsc --noEmit",
"lint": "eslint . --rule '@typescript-eslint/no-explicit-any: warn'"
}
}
// ESLint rule to block new .js test files after migration threshold
// .eslintrc: "no-restricted-syntax": warn on new .js in /tests