TypeScript 7.1 Beta: What's New (Source Phase Imports, --target es2026, Content Mappers, the Preview API) and How to Try It
TypeScript 7.1 beta: source phase imports, --target es2026, import attributes in ambient modules, content mappers and the preview API, plus how to install it.
TypeScript 7.0, released in August 2026, was the first stable release built on the TypeScript 7 native compiler, the Go port many people first met as tsgo in the @typescript/native-preview package announced in March 2025, which passed 8.5 million weekly downloads before 7.0 shipped. Microsoft's own numbers for 7.0 were an 11.9× faster full build of VS Code (125.7 s down to 10.6 s), about 18% less memory, and typically 8× to 12× on full builds elsewhere. It also turned the 6.0 deprecations into hard errors and made strict and esnext the defaults.
What 7.0 did not ship was a stable programmatic API. That is why typescript-eslint, the Vue, Svelte, Astro, MDX and Angular tooling, and the webpack loaders were still waiting on the old compiler. The TypeScript 7.1 beta, announced by Daniel Rosenwasser on 20 October 2026, is the release that starts closing that gap, alongside a handful of language and lib additions. This is a practical walkthrough: install it, try each feature, and decide whether to adopt it now.
Install the beta next to your current TypeScript
The beta is published under the beta tag of the regular typescript package. Nightlies are back on that package too, under next.
npm install -D typescript@beta
npx tsc -vIf a tool in your chain still needs the 6.0 API, keep @typescript/typescript6 installed alongside. It provides a tsc6 binary and the 6.0 API side by side with 7.x, so a project can type-check with the native compiler while a loader or lint rule keeps talking to the old one. The recommended migration path has not changed: adopt 6.0 first, fix its deprecation warnings, then move to 7.x.
Source phase imports
Source phase imports let you import a module's source rather than its evaluated namespace, with import source mod from "./x.wasm". Only the default import form exists. The result is typed as AbstractModuleSource, a new global in lib.esnext.d.ts; for WebAssembly it is a WebAssembly.Module you can hand straight to WebAssembly.instantiate.
import source mathModule from "./math.wasm";
const { instance } = await WebAssembly.instantiate(mathModule, {
env: { log: (n: number) => console.log(n) },
});
const add = instance.exports.add as (a: number, b: number) => number;
console.log(add(2, 3));
// Dynamic form
const again = await import.source("./math.wasm");Requirements: --module esnext, nodenext or preserve, and esnext in --lib or as the --target. Identity is preserved, so importing the same source twice gives the same object. The work landed in PR #63915 by Oleksandr Tarasiuk. Wasm source imports already work in recent Node.js versions; JS source imports are typed but cannot do much yet, because the runtime side of that proposal is still catching up. If lazy loading rather than source access is what you want, `import defer` is the other new import form, and the two solve different problems.
--target es2026: what you can finally type without lib hacks
--target es2026 and --lib es2026 are stable in 7.1. The lib picks up Math.sumPrecise, Iterator.concat, JSON.rawJSON, Error.isError, Array.fromAsync, Map and WeakMap getOrInsert / getOrInsertComputed, and the Uint8Array base64 and hex methods. If you have been carrying a local .d.ts to declare any of these, delete it after upgrading.
const counts = new Map<string, number>();
for (const word of ["a", "b", "a"]) {
counts.set(word, counts.getOrInsert(word, 0) + 1);
}
const rows = await Array.fromAsync(readLinesAsync("data.txt"));The methods themselves are covered in the Array.fromAsync guide and the ES2026 Error.isError, Map.getOrInsert and Uint8Array base64 post. Beyond ES2026, --lib esnext adds types for proposals still in flight: Promise.allKeyed, Promise.allSettledKeyed, Iterator.zip, Iterator.zipKeyed, and Iterator.prototype.chunks, .join and .includes. The target only affects types and downlevelling; the runtime still has to support the method.
Import attributes in ambient module declarations
Wildcard ambient declarations can now carry an import attribute, so you can describe what import sheet from "./x.css" with { type: "css" } resolves to. The built-in libs do not ship these declarations; you write them yourself:
declare module "*.css" with { type: "css" } {
const sheet: CSSStyleSheet;
export default sheet;
}
declare module "*.txt" with { type: "text" } {
const text: string;
export default text;
}
declare module "*.bin" with { type: "bytes" } {
const data: Uint8Array;
export default data;
}Importing one of those specifiers without the required attribute is now an error, which catches the case where a bundler would otherwise hand you a string when you expected a stylesheet. The attributes are not checked against anything on disk; they only select the declaration. This is PR #63931.
The preview API (typescript/sync)
The headline for tool authors. 7.1 adds preview entry points: typescript/sync (a synchronous client exposing options, the type checker and programs), typescript/async, typescript/fs (request-scoped full and layered filesystems), typescript/ast (node types, SyntaxKind, ScriptTarget), typescript/ast/is (type guards) and typescript/ast/factory (the create* and update* functions). A minimal check-and-emit looks like this:
import { API } from "typescript/sync";
using api = new API();
const parsed = api.parseCommandLine(["--strict", "src/index.ts"]);
using program = api.createProgram(parsed);
for (const diagnostic of program.getSemanticDiagnostics()) {
console.log(diagnostic.messageText);
}
program.emit();
// or: const output = program.emitToString();The announcement's own example follows the same shape (import { API } from "typescript/sync", using api = new API(), api.parseCommandLine, api.createProgram, then program.emit()), and it collects diagnostics from four program methods: getGlobalDiagnostics(), getProgramDiagnostics(), getSyntacticDiagnostics() and getSemanticDiagnostics(), formatted with formatDiagnosticsWithColorAndContext. The sketch above only reads the semantic ones; add the other three for a full tsc-style report. Both API and Program are Disposable, so using works, and api.close() / program.dispose() are the explicit forms. Incremental use goes through snapshots: api.createSnapshot, then snapshot.update() with fileNotifications and ensurePrograms. For in-memory testing there are createFileSystem, createFileSystemWithLib, createFileSystemLayer and removedPaths.
The honest caveats: it is a preview, it does not read tsconfig.json and has no --project equivalent yet, so you pass options and root files yourself, and there is no built-in watching. It is enough to prototype a lint rule or a loader against, not enough to replace the 6.0 API in production tooling this month.
Content mappers
Content mappers are how non-TS files (a .vue single-file component, an .mdx page, a CSS module) get type-checked by the native compiler without the compiler knowing each format. A mapper is an executable registered in tsconfig.json that turns a file's content into TypeScript the checker can read:
{
"compilerOptions": { "strict": true },
"contentMappers": [
{
"package": "@vue/content-mapper",
"extensions": [".vue"],
"options": { "target": 3.5 }
}
]
}Mappers run for every matching file in the program. Because they are executables, the CLI requires an explicit tsc --runExternalCode, and VS Code requires workspace trust plus a per-mapper permission behind the js/ts.contentMappers.enabled setting. Prototypes exist for Astro, CSS Modules, Ember, MDX, Svelte and Vue, plus a sample HTML mapper. Note that @vue/content-mapper in the example above is the package name used in the announcement and is not on npm yet; check the current listing before copying it into a real config.
Performance: 7.0 vs 7.1 beta
The announcement's --noEmit numbers with 4 checker threads, 7.0 against the 7.1 beta:
- bluesky: 4.48 s → 3.89 s (1.2×), memory −15.8%.
- mui-docs: 22.2 s → 11.9 s (1.9×), memory −49.6%.
- sentry: 19.6 s → 15.1 s (1.3×).
- t3code-server: 26.5 s → 19.1 s (1.4×).
- vscode: 21.6 s → 17.7 s (1.2×).
The parallelism flags from 7.0 still apply: --checkers and --builders set the thread counts, and --singleThreaded turns it all off for debugging or constrained CI runners. If you are also moving to running TypeScript directly in Node, the type-stripping guide covers where tsc still belongs in that setup.
Breaking change: distributive conditional types
One behaviour change can turn code that compiled on 7.0 into an error. Inside a distributed branch of a conditional type, the type parameter is now treated as a narrower, separate type (issue #63708, fixed in PR #64237). Recursive helpers written like this are the usual casualty:
// May now error: inside the branch, A is a narrower type and the
// A extends B constraint no longer holds the way it did before.
type Show<A extends B, B> = A extends B ? never : Show<A, B>;The fixes the team suggests are to drop constraints that were not doing real work, or to add a conditional check inside the branch before recursing. Separately, changes to how the DOM lib is generated may shift some type checks (#63702). No deprecations or removals are listed for 7.1.
Should you upgrade now? (When not to)
Try it locally today; be careful about CI. Specific reasons to wait:
- Your build depends on the compiler API. webpack loaders, typescript-eslint type-aware rules and framework language tooling are still waiting on API stabilisation. The preview API exists for them to build against, not for you to assume they have.
- You pin versions in CI. A beta moves; the RC and final may change behaviour again, and a lockfile pinned to a beta is a bug report waiting to happen.
- You hit the conditional-type change. Type-level libraries with heavy distributive recursion should run the beta in a branch and read the errors before committing to it.
- You need the old API anyway. Keep
@typescript/typescript6installed for tooling that requires it; that is what it is for.
If none of those apply, a straightforward app on 7.0 gains lib types, faster checks and the source phase syntax for very little risk.
What's next
The release candidate is expected about a month after the beta, with the final release shortly after. The API will stay preview-labelled until the team says otherwise, so treat typescript/sync and its siblings as something to prototype against and report issues on, and keep the 6.0 compatibility package around until your tooling says it no longer needs it.