Why whole-project conversion stalls
Turning on strict checking across an existing JavaScript codebase produces a long list of errors in code nobody has reviewed for years. The TypeScript handbook describes strictness as a dial you can turn up as far as you want and suggests enabling strict options early if you plan to use them, then renaming files one at a time. Teams that try everything at once tend to reach for any, which gives up the checking they wanted. Scope the conversion to a folder that can be finished and judged.
- Choose the area where the bugs actually come from.
- Pick a size that a reviewer can read in a sitting.
Let JavaScript and TypeScript coexist
The allowJs option lets the compiler accept existing JavaScript files alongside TypeScript, and the noEmit option lets your current build tool keep producing the output while the compiler only checks. You can see what TypeScript would report on a JavaScript file without renaming it: a comment at the top of a file turns checking on for that file, and the checkJs option turns it on for all of them. In JavaScript files the rules are looser, with parameters optional and object literals open-ended, so a clean JavaScript check is a lower bar than a clean TypeScript one.
- Run the check on the target folder first and count the errors.
- Rename files one at a time, in separate commits, so one can be undone.
A strict area that only grows
The strict option turns on the whole strict family, including noImplicitAny and strictNullChecks. Apply it to the converted folder through a second configuration that includes only that folder, and add the next folder to it when it is ready. Strictness never goes down. Give the folder's exports and the data that crosses its boundary real types. The handbook calls any the easiest escape hatch and the one that benefits you least, so each remaining any or suppression comment should be listed with a reason.
- Count any in exported signatures; the target is none.
- A non-null assertion is a claim you are making; review each one.
What types do not do
Types are checked when code is compiled, not when it runs, so they do not validate data arriving from an API or a file. A correct type for a response can still be wrong for a particular reply. Runtime validation is separate work. Types also do not change behaviour: a good conversion is renames, annotations and build support, with the existing tests passing unchanged before and after.
- Do not combine a conversion with a refactor.
- Keep the type-check command in CI so errors cannot return.
What does not fit, and how the fixed job is accepted
Tangled folders, code that adds properties at runtime in many places and projects that cannot run their tests do not fit a small fixed job. The fixed conversion covers one folder of up to 30 files and about 4,000 lines, and is accepted when the strict type check passes with no emitted files, exported signatures have no any, every suppression is justified in a report, the tests and build pass as before, and CI fails on a deliberately introduced type error. Send the folder name, size and build tool, not code. Prices are untested proposals; payment follows the agreed checks.
Sources and limits
- TypeScript handbook: migrating from JavaScript Checked 2026-10-11.
- allowJs lets TypeScript accept existing JavaScript files; files can be renamed to .ts one at a time and strictness is a dial that can be raised as far as wanted.
- noImplicitAny flags where TypeScript silently falls back to any; any is the easiest escape hatch and benefits you least.
- TSConfig reference: checkJs Checked 2026-10-11.
- checkJs reports type errors in JavaScript files and is equivalent to putting // @ts-check at the top of every JavaScript file; allowJs includes JavaScript in the project.
- TypeScript handbook: type checking JavaScript files Checked 2026-10-11.
- In JavaScript files parameters are optional by default, object literals are open-ended and JSDoc annotations override the default inference.
- TSConfig reference: strict and noEmit Checked 2026-10-11.
- strict enables the strict-mode family of options including noImplicitAny and strictNullChecks; noEmit stops the compiler writing output so another tool can build while TypeScript only checks.