Why TypeScript Is Taking Over JavaScript Projects
I walk through the adoption data, the practical day-to-day wins, the native compiler story, and the honest cases where plain JavaScript still makes more sense.

More developers now write only TypeScript than write only JavaScript. That’s not a prediction about where things are heading — it’s what the State of JavaScript 2024 survey found. The “100% TypeScript” group is the single largest segment. The “0% TypeScript” group is the smallest.
That particular inversion happened faster than most people expected, and the momentum hasn’t slowed. But adoption numbers alone don’t explain why TypeScript won. They just confirm that it did. The more useful questions are what makes it genuinely useful day to day, whether the old objections still hold, and where plain JavaScript still makes more sense.
I’m going to walk through the data, the practical wins, the big compiler story from 2025, and the cases where the answer honestly isn’t TypeScript.
On this page
- The numbers don’t leave much to debate
- Three things that change once you have types
- The speed complaint was real — and it’s being fixed
- The objections worth taking seriously
- Where TypeScript still loses
- The question has already changed
The numbers don’t leave much to debate
The State of JavaScript 2024 survey asked respondents how they divide their time between TypeScript and JavaScript. The result: 67% write more TypeScript than JavaScript. The average respondent writes about 74% TypeScript. The largest single group — roughly 3,900 people out of about 11,400 — writes nothing but TypeScript.
The Stack Overflow Developer Survey 2024 shows the same trend from a different angle. TypeScript ranked fifth overall at 38.5% usage, and fourth among professional developers at 43.4%. A language that didn’t exist until 2012 now sits above Go, Rust, and C# among working developers.
What I find more telling than the usage numbers is the wishlist. The same State of JS survey asked what’s missing from JavaScript. Static typing came in first — 5,403 respondents, ahead of a standard library and signals. And when asked how they’d want native types implemented, 8,362 out of about 10,400 chose “as similar to TypeScript as possible.” The community isn’t just using TypeScript because it’s available. It’s shaping what JavaScript itself should eventually become.
Three things that change once you have types
The description of TypeScript as “JavaScript with types” is technically accurate but undersells what those types actually do in practice.
Editor autocomplete goes from helpful to accurate. Without types, your editor guesses what methods and properties are available on an object. With types, it knows exactly. The difference matters most for objects that flow through several layers of a codebase — API responses, config objects, database records. Without types, each layer is a trust exercise. With types, the editor catches the mismatch before you save the file.
Rename is trustworthy. “Find all references” in a JavaScript codebase finds textual matches. Rename a function called formatDate and you’d better verify that none of the hits are a different formatDate from a different module. In a typed codebase, the editor knows which references point to the same binding. Rename-symbol works correctly across files and modules. That’s not a convenience feature — it’s why larger teams can refactor without searching and hoping.
Function signatures become honest documentation. Compare these two:
// Without types — you need to read the body to understand what this expects
function processOrder(order, options) { ... }
// With types — the contract is on the label
function processOrder(order: Order, options: ProcessOptions): Promise<Receipt> { ... }
The second version tells a reviewer, a new team member, and your future self exactly what the function requires and what it returns — without opening it. The types don’t replace documentation; they make documentation impossible to leave out of date, because the checker enforces it on every build. If you add a required field to Order and forget to update a call site, the compiler finds every missed spot. A comment in a doc file never gets that treatment.
If you want the full picture on how TypeScript’s type system works, TypeScript for JavaScript Developers covers the contract mindset that makes the whole thing click. The generics side — how types compose — is in TypeScript Generics.
The speed complaint was real — and it’s being fixed
For years the most legitimate criticism of TypeScript on large codebases was build time. The current JavaScript-based compiler is single-threaded. Add a few hundred thousand lines of code and builds start measuring in minutes. Editor startup slows. “Go to definition” lags. The developer experience degrades exactly where TypeScript’s benefits matter most.
That complaint is being addressed directly. In March 2025, Anders Hejlsberg announced a native port of the TypeScript compiler and language service, written in Go (codenamed “Corsa,” planned to ship as TypeScript 7). The numbers from that announcement are worth looking at directly:
| Codebase | Lines of code | Current | Native | Speedup |
|---|---|---|---|---|
| VS Code | 1,505,000 | 77.8s | 7.5s | 10.4x |
| TypeORM | 270,000 | 17.5s | 1.3s | 13.5x |
| Playwright | 356,000 | 11.1s | 1.1s | 10.1x |
| tRPC (server + client) | 18,000 | 5.5s | 0.6s | 9.1x |
Editor load time for the VS Code codebase drops from 9.6 seconds to 1.2 seconds — an 8x improvement before you write a single line. Memory usage roughly halves.
By May 2025, the native preview became available on npm as @typescript/native-preview, alongside a VS Code extension. The command is tsgo, which runs the same way as the existing tsc. Feature parity is still in progress — declaration emit, --build mode, and some language service features are not yet complete — but the core typechecking is working on most real-world projects.
The current JS-based compiler will continue under the 6.x release line during this transition. TypeScript 7 is the Go-based version. If build time has been your reason to avoid TypeScript on larger projects, the timeline for that problem shrinking is now measurable in months, not years.
The objections worth taking seriously
“TypeScript doesn’t catch runtime bugs.”
This is true and matters to understand clearly. TypeScript’s checker runs at compile time. Once the code executes, every annotation is gone. If an API returns a different shape than your interface declares, TypeScript won’t notice — it already did its job and left. For data that arrives from outside your codebase, you need runtime validation: Zod, Valibot, or similar. TypeScript handles internal consistency. It doesn’t replace input validation. Knowing this boundary is what stops people from being surprised by runtime errors in typed code.
“The setup overhead isn’t worth it for a small project.”
That’s a fair calculation. For a 150-line script that runs once, configuring a tsconfig.json adds more time than it saves. TypeScript’s value compounds over time and across teams. The return on investment is lower for something that won’t grow or be shared. If you’re writing a quick utility that you’ll use once, plain JavaScript is the right choice.
“Types add friction to every change.”
They do initially. Adding an annotation requires you to think explicitly about what a thing is, and that takes a moment you didn’t need to spend in JavaScript. Most teams report that friction shifting over a few weeks — the mental model becomes automatic, the annotations become fast to write, and the errors the checker prevents start saving more time than the typing costs. But the initial friction is real. It’s not zero.
Where TypeScript still loses
TypeScript doesn’t win everywhere, and saying so clearly is more useful than pretending it does.
Short scripts and one-off experiments. If the code lives for a day and fits in one file, setup time doesn’t justify itself. JavaScript is the right tool.
Runtime type safety. As the objections section covers, any data that crosses a trust boundary — user input, API responses, file reads — needs runtime validation regardless of how carefully typed your internal code is. TypeScript verifies that your internal contracts are consistent. It can’t verify that the outside world keeps its promises.
Heavily dynamic patterns. Code that deliberately manipulates object shapes at runtime — functions that return different structures based on complex conditions, proxy-based patterns, certain metaprogramming approaches — can produce TypeScript type signatures that are harder to read and reason about than the equivalent plain JavaScript. TypeScript can model most of these patterns, but sometimes the type machinery costs more than it’s worth.
There’s also a longer-horizon consideration: the TC39 Type Annotations proposal (Stage 1 at the time of writing) would allow JavaScript runtimes to skip over type syntax without a compile step. If that advances, some of the toolchain complexity TypeScript currently carries could become optional. That’s still speculative — Stage 1 means “worth exploring,” not “this is happening” — but it would meaningfully shift the tradeoff for smaller projects.
The question has already changed
A few years ago, the conversation in most teams was “should we adopt TypeScript?” In most professional JavaScript contexts now, that conversation has become “what would it take to justify staying with plain JavaScript?” That’s a meaningful inversion.
The shift shows up in the tooling: major frameworks generate TypeScript projects by default. It shows up in the npm registry: most popular packages ship type definitions. It shows up in the job market and code review: unannotated JavaScript increasingly prompts the question “why isn’t this typed?”
None of that makes JavaScript obsolete — the runtime is still JavaScript, and enormous amounts of working code won’t be migrated. But for new projects, for codebases that are growing, and for teams that want refactoring to feel reliable, the ecosystem has made the default decision.
If you’re starting something new today, use TypeScript with "strict": true from the first file. If you’re migrating an existing project, the approach I describe in TypeScript for JavaScript Developers — rename one file at a time with allowJs enabled — is still the gentlest path. Either way, focus annotations on the boundaries: function parameters, return types, module exports. Let inference handle the rest. Add runtime validation for anything arriving from outside.
The type checker doesn’t write better code for you. It makes the code you write easier to change with confidence — and that matters more the longer a project runs.