TypeScript 6.0 Is Out, and It's the End of an Era

TypeScript 6.0 dropped today. It's the last version of TypeScript written in TypeScript. Strict mode is on by default, ES5 is gone, outFile is dead, and TypeScript 7.0 — rewritten in Go — is right behind it. Here's everything that changed and what you actually need to do.

TypeScript 6.0 shipped today!

Mark that date. This is the last version of the TypeScript compiler written in TypeScript. From 7.0 onward, the compiler runs on a Go-based codebase called Project Corsa. The era of TypeScript checking itself is over.

That's the headline. Everything else in this release is a bridge: new defaults that reflect what the ecosystem already looks like, deprecations that clear the path for the Go compiler, and a handful of real language improvements. But the story here is bigger than any single feature. Microsoft is replacing the engine while the car is still moving, and 6.0 is where they tell you to buckle up.

If you haven't thought deeply about whether TypeScript is even worth it for your projects, I've already written about that. Go read the JavaScript vs TypeScript article — it covers the full tradeoffs. Come back when you've decided you're staying.

Why This Version Is Different

TypeScript 6.0 is the last release based on the current JavaScript codebase. The team is working on a new compiler and language service written in Go that takes advantage of native code speed and shared-memory multi-threading. That new codebase will be the foundation of TypeScript 7.0 and beyond.

TypeScript 6.0 acts as a bridge release between TypeScript 5.9 and 7.0. It deprecates features to align with 7.0 and is designed to be highly compatible in terms of type-checking behavior. There is no intention to produce a TypeScript 6.1 release, though patch releases for 6.0 are possible.

The Go rewrite isn't some far-off promise either. Type checking in the Go compiler has reached near-complete parity with only 74 test case gaps out of 20,000 test cases. The Go compiler already works for type checking. It's already in VS Code as a preview extension. It's already on npm as @typescript/native-preview. TypeScript 7.0 is close enough that the team is actively telling you to try it alongside 6.0.

That context matters for reading this release. A lot of 6.0's changes only make sense once you understand they're about clearing the runway for Go.

What Actually Changed in TypeScript 6.0

New Defaults That Reflect Reality

The compiler now defaults to strict mode, with module set to esnext and target pointing to ES2025. That means if your tsconfig.json didn't have "strict": true before, it does now. Projects with implicit any parameters are going to light up.

The types field now defaults to an empty array instead of pulling in all @types packages. Microsoft says this change alone improved build times by 20-50 percent in tested projects.

Think about what that means. Every project on TypeScript 5.x that didn't set an explicit types array was silently loading every @types/* package in node_modules. Every single one. You'd install @types/node for your server code and TypeScript would load @types/jest, @types/mocha, whatever else was in there. Slowing your build without you knowing why. TypeScript 6.0 fixes this. You now declare exactly what you want.

The error you'll hit if you don't update:

Cannot find name 'describe'. Do you need to install type definitions for a test runner?

Try `npm i --save-dev @types/jest` and then add 'jest' to the types field in your tsconfig.

That's TypeScript telling you to be explicit. Add "types": ["node", "jest"] (or whatever runtime you're using) and the error goes away.

rootDir now defaults to the directory containing tsconfig.json rather than being inferred from the input file set. This eliminates parsing overhead and makes project structure more predictable.

If you had this working before without setting rootDir explicitly, you'll probably see output writing to dist/src/index.js instead of dist/index.js. The fix: add "rootDir": "./src" to your tsconfig. Simple.

Improved Type Inference for Method Syntax

This is the most interesting language change in 6.0 and it fixes a long-standing inconsistency that's been tripping people up for years.

Arrow functions and method syntax behaved differently during generic type inference. Here's the problem the team fixed:

declare function callIt<T>(obj: {
    produce: (x: number) => T,
    consume: (y: T) => void,
}): void;

// This was the arrow syntax -- it worked fine in TS 5.x
callIt({
    consume: y => y.toFixed(),
    produce: (x: number) => x * 2,
});

// This is the method syntax —- it was broken in TS 5.x when 'consume' came first
callIt({
    consume(y) { return y.toFixed(); },
    //     ^ Error: 'y' is of type 'unknown'
    produce(x: number) { return x * 2; },
});

The issue was subtle: most functions written with method syntax have an implicit this parameter, but arrow functions do not. TypeScript treated method-syntax functions as contextually sensitive (meaning they were deprioritized during type inference) even when this was never actually used.

TypeScript 6.0 fixes this. If this is never actually used in a function, it is no longer considered contextually sensitive. That means method-syntax functions get higher priority in type inference, and both examples now work without errors.

This is a genuine improvement. You were writing correct code, TypeScript was wrong about it.

#/ Subpath Imports

Node.js package imports let you create internal path aliases inside a package using an imports field in package.json. The problem: you always had to write something after the #, like #root/ or #app/. You couldn't just use #/ as a clean prefix the way bundlers let you use @/.

Node.js recently added support for subpath imports starting with #/, and TypeScript 6.0 now supports this under the nodenext and bundler module resolution options.

{
  "imports": {
    "#/*": "./dist/*"
  }
}
import * as utils from "#/utils.js";

Clean. No more #root/ prefix that carried no meaning. If you're using nodenext or bundler module resolution and wanted this, it's there now.

Temporal API Types Built In

TypeScript 6.0 includes built-in type definitions for JavaScript's Temporal API. Firefox shipped Temporal in May 2025, Chrome followed in January 2026, and Safari support is actively in development.

Date has been broken since JavaScript was invented. Mutable, timezone-naive, no concept of calendar systems, and precision capped at milliseconds. The Temporal API fixes all of this with an immutable, timezone-aware replacement. TypeScript can now check your Temporal code without a third-party package.

const yesterday = Temporal.Now.instant().subtract({ hours: 24 });
const tomorrow = Temporal.Now.instant().add({ hours: 24 });

If your target runtime supports Temporal (or you polyfill it), TypeScript 6.0 will type-check it correctly. This is one of those things that should have shipped years ago and is overdue.

Map.getOrInsert

TypeScript 6.0 adds types for the ECMAScript getOrInsert Map method, part of the "upsert" proposal.

Before:

function processOptions(options: Map<string, unknown>) {
  let strictValue: unknown;
  if (options.has("strict")) {
    strictValue = options.get("strict");
  } else {
    strictValue = true;
    options.set("strict", strictValue);
  }
}

After:

function processOptions(options: Map<string, unknown>) {
  const strictValue = options.getOrInsert("strict", true);
}

TypeScript 6.0 now types getOrInsert and getOrInsertComputed correctly. Your code stays the same; TypeScript just stops complaining about it.

RegExp.escape Types

TypeScript 6.0 adds support for the RegExp.escape ECMAScript proposal, which reached Stage 4 and is now officially part of the language.

const userInput = "hello.world[test]";
const safePattern = RegExp.escape(userInput);

// This will return "hello\\.world\\[test\\]"
const regex = new RegExp(safePattern);

Building regex patterns from user-supplied strings without escaping them is a bug. RegExp.escape is the standard fix. TypeScript 6.0 types it.

What's Deprecated and What's Dead

This is the part that's going to bite people. Some of this is deprecation (works with a warning, gone in 7.0). Some of it is already gone.

ES5 Target: Deprecated

The ECMAScript 5 target was important for a long time to support legacy browsers, but ES2015 was released over a decade ago and all modern browsers have supported it for many years. TypeScript's lowest supported target is now ES2015, and target: es5 is deprecated.

Internet Explorer is dead. It has been dead. If you're still shipping ES5 output because of IE, you have bigger problems than your TypeScript config. If you genuinely need ES5 output (some enterprise situations do require it), run an external transpiler like Babel on TypeScript's output. TypeScript's job was never to be a cross-compiler; it just did it because nobody else was around to do it.

--outFile: Gone

--outFile has been removed entirely from TypeScript 6.0. The option concatenated multiple input files into a single output. Webpack, Rollup, esbuild, Vite, and Parcel all do this faster and with far more configurability. Removing it simplifies the implementation and lets TypeScript focus on type-checking and declaration emit.

Worth noting: zero community members raised concerns about outFile removal in the deprecation tracking issue. Tests on the top 800 GitHub repos showed no breakage. Nobody was using it. Or at least, nobody who was using it was paying attention.

AMD, UMD, SystemJS: Gone

If you're on AMD modules, you're probably running something old enough that this migration is going to involve more than just a TypeScript version bump. The module format answers are now: CommonJS, ESM, or bundler. That's it.

baseUrl: Deprecated

baseUrl is deprecated and no longer serves as a module lookup root in TypeScript 6.0.

The fix is mechanical. Move the baseUrl prefix directly into your paths entries:

// The old way we are all used to
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@app/*": ["app/*"]
    }
  }
}

// The new way 
{
  "compilerOptions": {
    "paths": {
      "@app/*": ["./src/app/*"]
    }
  }
}

The ts5to6 migration tool automates this. Use it.

Node10 Module Resolution: Deprecated

The node (also known as node10) module resolution mode is deprecated. It modeled Node 10's behavior but doesn't match modern Node's ESM and resolution semantics.

Use nodenext or bundler. If you're on a Vite or webpack project, bundler is what you want. If you're writing a Node.js application or library, nodenext.

module Keyword for Namespaces: Deprecated

TypeScript originally used module Foo {} to declare namespaces. Then the language switched to namespace Foo {}. The old syntax has been deprecated for years. Now it errors. If you still have module Foo {} syntax anywhere, update it to namespace Foo {}. Find-and-replace, done.

Import Assertions: Deprecated

// The old way now with errors
import data from "./data.json" assert { type: "json" };

// The new way by importing attributes
import data from "./data.json" with { type: "json" };

assert was the original syntax from an earlier proposal draft. The TC39 proposal changed it to with. TypeScript 6.0 deprecates assert across both static imports and dynamic import() calls.

How to Migrate

Install TypeScript 6.0:

npm install -D typescript

Run the compiler and see what breaks. For a modern project (Vite, strict mode already on, using ESM), the upgrade is probably under an hour. For legacy projects with AMD modules, ES5 targets, or --outFile, expect real work.

The Escape Hatch

Setting "ignoreDeprecations": "6.0" in your tsconfig.json silences all 6.0 deprecation warnings. Note that this will not work in TypeScript 7.0 — deprecated options are being removed entirely in the Go compiler.

Use this to upgrade on your timeline, not all at once. But understand it's a temporary painkiller, not a fix.

The Migration Tool

npx ts5to6 ./tsconfig.json

The ts5to6 tool, written by Andrew Branch of the TypeScript team, automates the two most disruptive config migrations: baseUrl removal and rootDir inference. It works across monorepos, follows project references, and handles extends chains.

Run it before doing anything manually.

Quick Migration Checklist

  1. Set an explicit "types" array in tsconfig.json
  2. Set "rootDir": "./src" explicitly if you had it inferred
  3. Replace "target": "es5" with "target": "es2015" minimum
  4. Replace import ... assert {} with import ... with {}
  5. Replace --moduleResolution node with nodenext or bundler
  6. Move baseUrl into paths entries (or run ts5to6)
  7. Remove --outFile and use a bundler
  8. Rename any module Foo {} namespaces to namespace Foo {}

Community reports put compatibility at around 95% with TypeScript 5.x, with most modern projects migrating in under an hour. Legacy applications using ES5 targets, --outFile, or non-strict mode face real manual migration work.

TypeScript 7.0 Is Right Behind This

The Go rewrite is not vaporware. The native toolset is now stable enough for broad daily use in editors and for command-line type checking, delivering big speed gains and near-complete type-checking parity.

You can try it right now:

npm install -D @typescript/native-preview

Or install the VS Code extension called "TypeScript Native Preview" from the marketplace.

The remaining gaps in TypeScript 7.0: JavaScript emit isn't fully ported, downlevel compilation only goes back to ES2021 (no decorator emit), and the old Strada API that many third-party tools depend on isn't supported yet. Those gaps will close. The team says 7.0 ships soon after 6.0.

What does 10x faster compilation feel like on a large project? We'll find out.

The Conclusion

TypeScript 6.0 is a cleanup release with real consequences. The new language features (better method inference, Temporal types, Map.getOrInsert, RegExp.escape) are useful and ship real value. The deprecations are overdue — ES5 targeting, AMD modules, --outFile, baseUrl as a path root — none of these belong in a modern TypeScript project.

The shift from JavaScript to Go for the compiler is genuinely significant. TypeScript self-hosting was a great story for a long time. A compiler written in the language it compiles is elegant, dogfooding at its best. But it also meant the compiler had to deal with JavaScript's performance ceiling — a single-threaded runtime, garbage collection, no real parallelism. Go removes all of those constraints. The same type system, native threads, no GC pauses, dramatically faster builds.

Upgrade 6.0. Fix your deprecations. Then start watching TypeScript 7.0. That's where the actual performance story lands.

For everything you need to understand about JavaScript and the runtime ecosystem that TypeScript sits on top of, the Node.js article covers the foundations. And if you're building on this stack with Bun — which strips TypeScript types natively at the runtime level — that's its own interesting piece of the puzzle worth understanding alongside what just changed in the compiler.