TypeScript Deep Dives · Part 1
TypeScript 7 is ~10× faster. Why your CI often only gets ~28%
TypeScript 7’s native compiler can deliver large speedups on a laptop, but shared CI runners often see far smaller gains. Here’s what the numbers mean and what actually moves build times.
The headline vs. the CI reality
TypeScript 7’s native compiler is a genuine leap. On a fast laptop, with type-heavy application code, teams report large speedups, sometimes approaching the “~10×” marketing number.
So why did one client’s CI only get about 28% faster?
Because CI is a different machine, with different constraints:
- Fewer or noisier cores than a developer laptop
- Cold or shared caches
- Full-program checks that still walk a large graph
- Workloads dominated by structure, not raw checker throughput
The native compiler is a gift. It does not rewrite a monorepo that re-checks everything on every PR.
What the real numbers look like
A useful way to talk about TypeScript 7:
| Context | Typical outcome |
|---|---|
| Type-heavy code, fast laptop | Large multi-fold speedups |
| Same project, shared CI runner | Often much smaller (tens of percent) |
| Project already incremental + referenced | Gains compound cleanly |
| Giant barrels + deep conditionals | Checker still pays for your graph |
Treat “10×” as best-case local type-check throughput, not a promise for every tsc invocation in every pipeline.
What actually moves build times
With or without TypeScript 7, the same patterns show up in audits:
- Barrel files,
index.tsre-exports that pull huge module graphs into every check - Giant unions & deep conditionals, type instantiations explode across call sites
skipLibCheckoff, re-checking.d.tsfromnode_modulesevery run- No incremental builds, no
.tsbuildinfocache locally or in CI - Monorepos without project references, one giant program instead of
tsc -b
Often the highest-ROI change is a one-line import fix:
// Before, pulls the whole components barrel into the check
import { Button } from "@/components";
// After, keeps the graph small
import { Button } from "@/components/Button";How to evaluate TypeScript 7 on your repo
- Record a baseline:
npx tsc --noEmit --extendedDiagnostics - Upgrade on a branch; keep the same
tsconfigshape first - Re-run the same command locally and in CI
- Compare wall-clock and check time, don’t only look at laptop numbers
- Only then invest in structural fixes (references, barrels, type complexity)
If CI barely moves but local feels transformed, you learned something useful: your bottleneck is environment + graph, not “TypeScript is slow.”
Bottom line
TypeScript 7 can make the checker dramatically faster. It will not rescue a build that is slow for structural reasons. Measure both environments, then fix config, types, and CI so the native compiler’s gains stick.
Want the short version? Your config. Your types. Your CI. Those still decide most of the bill.
FAQ
Is TypeScript 7 really 10× faster?+
On type-heavy code on a fast local machine, native TypeScript 7 can show multi-fold speedups (often cited in the ~3.9–10× range depending on workload). On shared CI runners with fewer cores and colder caches, the same project may only improve by tens of percent.
Will upgrading to TypeScript 7 fix a slow monorepo?+
Not by itself. Barrel files, giant unions, missing incremental builds, and a lack of project references still dominate type-check cost. The native compiler helps, but structural issues remain.
What should we measure before upgrading?+
Capture baseline times with `tsc --extendedDiagnostics` locally and in CI, then re-run after upgrading. Separate transpile time from full type-check time so you know which budget actually moved.
TypeScript Performance workshop
On-site with your team: we benchmark TypeScript 7 on your repo, then fix the structural bottlenecks so the speedup sticks.
View workshops →Keep learning
TypeScript `satisfies` vs `as`: stop silencing the compiler
`as` isn’t a conversion, it’s a promise. `satisfies` checks the value and keeps the exact inferred shape.
TypeScript generics that stop fighting you
Good generics constrain and infer. Callers pass values and get precise types back, with no `<T>` by hand.
Make TypeScript check your strings: template literal & mapped types
Model routes, events, and keys as types, not `string`, so typos become red squiggles before runtime.