When TypeScript earns its setup cost
TypeScript's setup cost depends on how long the code will live. An incremental migration lets a working JavaScript application gain types during ordinary maintenance.

In 2015, I was writing ES5 with jQuery. TypeScript added a compiler to satisfy while clients wanted features by Friday. I treated its triple-slash references as extra work for the kinds of projects banks ran.
I underestimated how often types would help with everyday development. Their adoption now gives me a reason to revisit what changed in the work.
Adoption in the 2025 survey
The State of JavaScript 2025 survey, published in February 2026, reported that 40% of respondents wrote exclusively in TypeScript. The corresponding figures were 34% in 2024, then 28% in 2022.
At the other end of the survey's scale, 6% reported writing exclusively in plain JavaScript.
Roughly two thirds of professional developers used TypeScript in some form, according to the figures discussed here. Satisfaction among users was in the mid-eighties. Those survey results describe adoption among respondents; they leave room for developers whose work still suits plain JavaScript.
When I first dismissed TypeScript, its adoption was in the low single digits.
The tools changed the cost
Build tooling reduced the initial setup burden. Editor support gave types an everyday use, while coding assistants added another reason to make function contracts explicit.
Modern runtimes can handle TypeScript, as can common bundlers. Framework templates often configure it at project creation. That removes setup work that once made the compiler difficult to justify on a small project.
Types also give an editor information for autocomplete. A rename can follow references across files when the editor understands which symbol they use. These are benefits you encounter while editing, before a type error prevents a build.
Function signatures give a coding assistant explicit information about inputs and return values. That reduces how much it has to infer from nearby code. It can still misunderstand a type or produce incorrect code, so I use type checking to constrain generated changes before reviewing their behavior.
Compiler settings affect the result
TypeScript code runs as JavaScript after its type syntax is removed. Type checking covers part of the development process; runtime failures still need their own validation.
I've seen teams suppress compiler errors with any, then find little benefit in the migration. Each use allows code to pass without the check the team intended to gain.
Strict settings make a different commitment. Treating any as a reason to inspect a boundary gives the compiler more of the assumptions it needs to check.
Short-lived scripts can stay in JavaScript
I still write plain JavaScript when the code's purpose makes the setup cost difficult to recover.
A small utility that runs twice before deletion may have no occasion to benefit from later refactoring. The same calculation can apply to a one-off migration or scraper. Even a small compiler configuration takes time, as does expressing types for code that will exist for only a few hours.
I use types when other people will maintain the code. An expected long life also justifies them, especially if the code is likely to need refactoring.
A temporary script can outgrow those assumptions. By the time several people depend on its 4,000 lines, the unrecorded expectations inside it can make a type migration expensive.
Migrate during existing work
The teams I meet often already have a working JavaScript application. They need a way to introduce types while continuing to ship it.
An incremental migration can follow this sequence:
- Enable TypeScript permissively with
allowJs. Keep strict flags off initially so the existing build passes; resolve build problems before converting files. - Write new files in TypeScript. This gives new work a consistent starting point.
- Convert an existing file when another change already requires understanding it.
- Enable one stricter flag at a time.
noImplicitAnyis often a starting point; resolve its errors before enabling the next flag. - Type API boundaries with the data models they exchange. These declarations let the compiler inspect assumptions that cross between parts of the application.
A quarter reserved for a complete migration can lose its time to delivery deadlines. An abandoned conversion leaves the team maintaining two languages without a procedure for finishing. Incremental work needs an agreed next step whenever a developer touches an unconverted file.
Compare the cost over the code's lifetime
Writing types adds work at the beginning of a file's life. The time they save depends on how often the file needs maintenance. That includes reading it to locate a change or repair a fault. Short-lived code has fewer opportunities to recover the initial cost.
I make the decision by asking how long the code will remain in use. Production applications often have enough future maintenance to justify types; a disposable script may have a different answer.
I work on React applications that need TypeScript migration or performance work, as well as refactoring when the existing architecture no longer fits the codebase.
Source: State of JS 2025 (InfoQ)