{"id":5473,"date":"2026-10-20T09:53:06","date_gmt":"2026-10-20T17:53:06","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=5473"},"modified":"2026-10-20T09:53:06","modified_gmt":"2026-10-20T17:53:06","slug":"announcing-typescript-7-1-beta","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-7-1-beta\/","title":{"rendered":"Announcing TypeScript 7.1 Beta"},"content":{"rendered":"<p>Today we&#8217;re excited to announce the beta release of TypeScript 7.1!<\/p>\n<pre class=\"prettyprint language-sh\" style=\"padding: 10px; border-radius: 10px;\"><code>npm install -D typescript@beta\r\n<\/code><\/pre>\n<p>Let&#8217;s take a look at what&#8217;s new in TypeScript 7.1!<\/p>\n<h2 id=\"support-for-import-attributes-in-ambient-modules\">Support for Import Attributes in Ambient Modules<\/h2>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/import\/with\">Import attributes<\/a> are metadata that are attached to import statements.\nTypically, they&#8217;re meant to instruct runtimes and bundlers on how to interpret the content of an import, as well as the shape of the resulting module.\nFor example,<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import myData from \".\/data\/someData.json\" with { type: \"json\" };\r\n<\/code><\/pre>\n<p>Everything in the object following the <code>with<\/code> keyword is an import attribute.\nEnvironments like browsers can&#8217;t simply decide how to deal with an import based on file name extensions like <code>.json<\/code>.\nSpecifying <code>type: \"json\"<\/code> tells whatever runtime that <code>someData.json<\/code> needs to be interpreted as a JSON file, parsed out, and provided via a default import (in our example above, that&#8217;s <code>myData<\/code>).<\/p>\n<p>The <code>type<\/code> attribute has become the de facto way for runtimes to customize this behavior.\n<a href=\"https:\/\/github.com\/tc39\/proposal-import-text\">ECMAScript (JavaScript) has a proposal<\/a> that allows code to specify <code>type: \"text\"<\/code>, which returns the import&#8217;s contents as a string.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import readme from \"..\/README.md\" with { type: \"text\" };\r\n\r\nconsole.log(readme);\r\n<\/code><\/pre>\n<p>There is <a href=\"https:\/\/github.com\/tc39\/proposal-import-bytes\">also a proposal<\/a> for <code>type: \"bytes\"<\/code> to return a <code>Uint8Array<\/code> of raw bytes.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import { pngToPixels, boxBlur } from \".\/photoUtils.js\";\r\n\r\nimport photo from \".\/myPhoto.png\" with { type: \"bytes\" };\r\nconst blurryPhoto = boxBlur(pngToPixels(photo));\r\n<\/code><\/pre>\n<p>Browsers have also allowed importing CSS files as <code>CSSStyleSheet<\/code>s with <code>type: \"css\"<\/code> for a few years now.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import someTheme from \".\/themes\/someCoolTheme.css\" with { type: \"css\" };\r\n\r\ndocument.adoptedStyleSheets.push(someTheme);\r\n<\/code><\/pre>\n<p>To support importing these files, people might use <em>ambient module declarations<\/em> in TypeScript using a wildcard pattern (e.g. <code>*.css<\/code>).<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>\/\/ You can write this in a global `.d.ts` file with no import statements.\r\n\r\ndeclare module \"*.css\" {\r\n    const content: CSSStyleSheet;\r\n    export default content;\r\n}\r\n\r\ndeclare module \"*.txt\" {\r\n    const content: string;\r\n    export default content;\r\n}\r\n\r\ndeclare module \"*.md\" {\r\n    const content: string;\r\n    export default content;\r\n}\r\n\r\ndeclare module \"*.bin\" {\r\n    const content: Uint8Array;\r\n    export default content;\r\n}\r\n<\/code><\/pre>\n<p>This is okay, but it doesn&#8217;t work for all environments as it doesn&#8217;t account for import attributes at all.<\/p>\n<p>You might ask why this is an issue &#8211; at first glance, it seems like the only problem is that it just allows people to accidentally leave off an import attribute.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>\/\/ \u274c oops, forgot an import attribute\r\nimport readme from \"..\/README.md\";\r\n\r\n\/\/ \u2705 what we were supposed to write\r\nimport readme from \"..\/README.md\" with { type: \"text\" };\r\n<\/code><\/pre>\n<p>But that is still a problem worth fixing.\nAnother issue is that it becomes repetitive.\nWith import attributes, the entire issue is that the runtime cares about the attributes, not the file extension.\nWe shouldn&#8217;t have to re-declare a pattern for both <code>.txt<\/code> and <code>.md<\/code> files if both were going to use <code>type: \"text\"<\/code>.<\/p>\n<p>But a major issue is that runtime environments may support different import attributes entirely, and may act differently depending on whether they&#8217;re present.\nFor example, bundlers might use a build-time feature called <a href=\"https:\/\/github.com\/css-modules\/css-modules\">CSS Modules<\/a> as the default behavior when importing <code>.css<\/code> files, but specifying the browser-supported <code>type: \"css\"<\/code> in the import statement will override this behavior and ensure the <code>.css<\/code> file is brought in as a <code>CSSStyleSheet<\/code> object.<\/p>\n<p>That&#8217;s why TypeScript 7.1 introduces support for import attributes in ambient module declarations.\nYou can now declare the following in your TypeScript projects, get an error if you try to import a file without the required import attributes, and get the correct type based on the import attributes.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>declare module \"*\" with { type: \"css\" } {\r\n    const content: CSSStyleSheet;\r\n    export default content;\r\n}\r\n\r\ndeclare module \"*\" with { type: \"text\" } {\r\n    const content: string;\r\n    export default content;\r\n}\r\n\r\ndeclare module \"*\" with { type: \"bytes\" } {\r\n    const content: Uint8Array;\r\n    export default content;\r\n}\r\n<\/code><\/pre>\n<p>Note that imports matching these declarations are not validated against files on disk.\nAs is currently the behavior when an import matches an ambient module declaration, failed lookups will be reported at runtime or during a bundler&#8217;s build process.<\/p>\n<p>Also note that these declarations are not shipped as part of the TypeScript built-in libraries.\nWe recommend libraries <strong>not<\/strong> include them in their published packages, and end-users will need to declare them in their own projects if necessary.\nThat will provide end-users with flexibility on how the global scope is configured (e.g. <code>lib.dom.d.ts<\/code> versus <code>@types\/node<\/code>) and will prevent conflicts with built-in declarations in the future.<\/p>\n<p>For more information, see <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/63931\">our implementing pull request here<\/a>.<\/p>\n<h2 id=\"source-phase-imports\">Source Phase Imports<\/h2>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/import\/source\">Source phase imports<\/a> are <a href=\"https:\/\/github.com\/tc39\/proposal-source-phase-imports\">a proposed new feature in ECMAScript<\/a>.\nThe feature introduces a new <code>source<\/code> modifier\/keyword that follows the <code>import<\/code> keyword.\nOnly default imports can be written with <code>import source<\/code>.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import source SomeModule from \"some-module\";\r\n<\/code><\/pre>\n<p>The idea with this feature is that when we use <code>import source<\/code>, we&#8217;ll get back an object that represents the module after it&#8217;s been parsed and analyzed by the runtime, but <em>before<\/em> its imports have been loaded (and therefore, before they have been validated or linked against other modules, and before any code contained in the module can run).\nThis object on its own is kind of &#8220;inert&#8221; &#8211; it&#8217;s an instance of something called an <code>AbstractModuleSource<\/code> which is <em>eventually<\/em> meant to be imported or instantiated.<\/p>\n<p>For WebAssembly (wasm) imports, that object will be an instance of a <code>WebAssembly.Module<\/code>.\nWhat&#8217;s useful with these objects is that they can be passed directly into <code>WebAssembly.instantiate<\/code>.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import source SuperFastThing from \".\/super-fast-thing.wasm\";\r\nimport { WASI } from \"node:wasi\";\r\n\r\nconst wasi = new WASI({ \/*...*\/ });\r\nconst fastThingInstance = await WebAssembly.instantiate(SuperFastThing, {\r\n    wasi_snapshot_preview1: wasi.wasiImport\r\n});\r\n\r\nwasi.start(fastThingInstance);\r\n<\/code><\/pre>\n<p>WebAssembly source imports are already supported <a href=\"https:\/\/beta.docs.nodejs.org\/esm#wasm-source-phase-imports\">in recent versions of Node.js<\/a>.<\/p>\n<p>At the moment, you can&#8217;t do much with a source import of a JavaScript file.\nThe spirit of the proposal implies at some point we might be able to pass a JavaScript module source directly into an <code>import()<\/code> call.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import source SomeModule from \".\/someModule.js\";\r\nconst moduleInstance = await import(SomeModule);\r\n<\/code><\/pre>\n<p>Another part of the idea with JavaScript source imports is that, over time, we may gain other features that will allow us to be able to customize behavior around how modules are loaded and instantiated, similar to how we did with <code>WebAssembly.instantiate<\/code> above.\nBut we&#8217;re not there yet, and in fact, many environments and tools still don&#8217;t currently support JavaScript source imports in the first place.<\/p>\n<p>Source imports aren&#8217;t limited to import statements though.\nYou can also perform a <em>dynamic<\/em> source import as well via the <code>import.source<\/code> meta-property function.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>const SuperFastThing = await import.source(\".\/super-fast-thing.wasm\");\r\nconst fastThingInstance = await WebAssembly.instantiate(SuperFastThing, {\r\n    \/\/ ...\r\n});\r\n<\/code><\/pre>\n<p>Source imports retain identity.\nThat means you can use them in <code>Map<\/code>s and <code>Set<\/code>s, or compare against them reliably.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>\/\/ Note that `WebAssembly.instantiate` always returns a distinct object.\r\nimport source source1 from \".\/plugin.wasm\"\r\nimport source source2 from \".\/plugin.wasm\"\r\nconst source3 = await import.source(\".\/plugin.wasm\");\r\n\r\nconsole.log(source1 === source2); \/\/ true\r\nconsole.log(source2 === source3); \/\/ true\r\n<\/code><\/pre>\n<p>When using <code>import source<\/code>, every imported module has the type <code>AbstractModuleSource<\/code>, a new global type in <code>lib.esnext.d.ts<\/code>.\nYou must have an appropriate <code>--module<\/code> setting (i.e. <code>esnext<\/code>, <code>nodenext<\/code>, or <code>preserve<\/code>) to use source imports, as well as the appropriate <code>esnext<\/code> option in <code>--lib<\/code> or <code>--target<\/code>.<\/p>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/63915\">This feature was implemented<\/a> thanks to the work of <a href=\"https:\/\/github.com\/a-tarasyuk\">Oleksandr Tarasiuk<\/a>.<\/p>\n<h2 id=\"target-es2026\"><code>--target es2026<\/code><\/h2>\n<p>TypeScript 7.1 now supports <code>es2026<\/code> as a stable <code>--target<\/code> and <code>--lib<\/code> option.\nOnly <code>lib<\/code> additions are significant, as declarations have been added, or moved from <code>esnext<\/code> as proposed features have stabilized in ECMAScript 2026.<\/p>\n<p>Stabilizations in <code>--lib es2026<\/code> include:<\/p>\n<ul>\n<li><code>Math.sumPrecise()<\/code><\/li>\n<li><code>Iterator.concat()<\/code><\/li>\n<li><code>JSON.rawJSON()<\/code><\/li>\n<li>A <code>JSON.parse()<\/code> overload for parsing with original text<\/li>\n<li><code>Error.isError()<\/code><\/li>\n<li><code>Map.prototype.*<\/code>\n<ul>\n<li><code>getOrInsert()<\/code><\/li>\n<li><code>getOrInsertComputed()<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>WeakMap.prototype.*<\/code>\n<ul>\n<li><code>getOrInsert()<\/code><\/li>\n<li><code>getOrInsertComputed()<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>Uint8Array.prototype.*<\/code>\n<ul>\n<li><code>toBase64()<\/code><\/li>\n<li><code>setFromBase64()<\/code><\/li>\n<li><code>toHex()<\/code><\/li>\n<li><code>setFromHex()<\/code><\/li>\n<\/ul>\n<\/li>\n<li><code>Uint8Array.fromHex()<\/code><\/li>\n<li><code>Uint8Array.fromBase64()<\/code><\/li>\n<li><code>Array.fromAsync()<\/code><\/li>\n<\/ul>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64096\">The work of<\/a> creating the new targets, as well as many of the declaration files themselves, was done thanks to <a href=\"https:\/\/github.com\/a-tarasyuk\">Oleksandr Tarasiuk<\/a>.<\/p>\n<h2 id=\"new-library-methods\">New Library Methods<\/h2>\n<p><code>--lib esnext<\/code> now includes a few proposed library methods in ECMAScript including:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/tc39\/proposal-await-dictionary\"><code>Promise.allKeyed<\/code> and <code>Promise.allSettledKeyed<\/code><\/a><\/li>\n<li><a href=\"https:\/\/github.com\/tc39\/proposal-joint-iteration\"><code>Iterator.zip<\/code> and <code>Iterator.zipKeyed<\/code><\/a><\/li>\n<li><a href=\"https:\/\/github.com\/tc39\/proposal-iterator-chunking\"><code>Iterator.prototype.chunks<\/code><\/a><\/li>\n<li><a href=\"https:\/\/github.com\/tc39\/proposal-iterator-join\"><code>Iterator.prototype.join<\/code><\/a><\/li>\n<li><a href=\"https:\/\/github.com\/tc39\/proposal-iterator-includes\"><code>Iterator.prototype.includes<\/code><\/a><\/li>\n<\/ul>\n<p>Support for these <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64093\"><code>Promise<\/code> methods<\/a> and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64095\"><code>Iterator<\/code> methods<\/a> was provided thanks to <a href=\"https:\/\/github.com\/a-tarasyuk\">Oleksandr Tarasiuk<\/a>.<\/p>\n<h2 id=\"typescript-71-api\">TypeScript 7.1 API<\/h2>\n<p>TypeScript 7.1 ships a new API that allows building powerful tools and utilities using our syntactic and semantic analyses.<\/p>\n<p>Rather than exposing a monolithic API, TypeScript 7.1 is organized into several entry points, each serving a specific purpose.<\/p>\n<table>\n<thead>\n<tr>\n<th>Entry point<\/th>\n<th>Purpose<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>typescript\/sync<\/code><\/td>\n<td>A synchronous compiler client, which supports compiler options, type-checker and program APIs<\/td>\n<\/tr>\n<tr>\n<td><code>typescript\/async<\/code><\/td>\n<td>A <code>Promise<\/code>-based equivalent of the sync client<\/td>\n<\/tr>\n<tr>\n<td><code>typescript\/fs<\/code><\/td>\n<td>Request-scoped full and layered filesystems<\/td>\n<\/tr>\n<tr>\n<td><code>typescript\/ast<\/code><\/td>\n<td>Syntax tree node (AST) types and enums such as <code>SyntaxKind<\/code> and <code>ScriptTarget<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>typescript\/ast\/is<\/code><\/td>\n<td>Node type guards<\/td>\n<\/tr>\n<tr>\n<td><code>typescript\/ast\/factory<\/code><\/td>\n<td><code>create*<\/code> and immutable <code>update*<\/code> functions<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Here&#8217;s an example of how to conduct a simple compilation using the TypeScript 7.1 API, with filenames and compiler options passed explicitly on the command line.\nUnlike <code>tsc<\/code>, this example does not discover or load a <code>tsconfig.json<\/code> file and does not support <code>--project<\/code>.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>\/\/ Compile explicit filenames using command-line compiler options.\r\n\r\nimport { API, formatDiagnosticsWithColorAndContext, type Diagnostic } from \"typescript\/sync\";\r\n\r\nusing api = new API();\r\nconst reportErrors = (diagnostics: readonly Diagnostic[]) =&gt; {\r\n    console.log(formatDiagnosticsWithColorAndContext(diagnostics, api))\r\n};\r\n\r\n\/\/ Parse command-line filenames and compiler options, report any errors.\r\nconst commandLineArgs = process.argv.slice(2);\r\nconst parsedCommandLine = api.parseCommandLine(commandLineArgs);\r\nif (parsedCommandLine.errors.length &gt; 0) {\r\n    reportErrors(parsedCommandLine.errors);\r\n    process.exit();\r\n}\r\n\r\n\/\/ Create the program by resolving and parsing all files in the entry point.\r\nusing program = api.createProgram(parsedCommandLine.fileNames, parsedCommandLine.options);\r\n\r\n\/\/ Collect and report any diagnostics from the program before emitting.\r\n\/\/ You can customize whether any of these block reporting errors in subsequent passes if desired.\r\nconst diagnostics = [\r\n    ...program.getGlobalDiagnostics(),\r\n    ...program.getProgramDiagnostics(),\r\n    ...program.getSyntacticDiagnostics(),\r\n    ...program.getSemanticDiagnostics(),\r\n];\r\nif (diagnostics.length &gt; 0) {\r\n    reportErrors(diagnostics);\r\n}\r\n\r\n\/\/ Emit files - this respects the `noEmitOnError` option,\r\n\/\/ so nothing will be emitted if an earlier step reported errors.\r\nconst emitResult = program.emit();\r\nif (emitResult.diagnostics.length &gt; 0) {\r\n    reportErrors(emitResult.diagnostics);\r\n}\r\n<\/code><\/pre>\n<p>Notice the <code>using<\/code> keyword in our declarations above.\nYou might not be familiar with <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/using\"><code>using<\/code> since it&#8217;s somewhat new in JavaScript<\/a>, but don&#8217;t fret.<\/p>\n<p><code>API<\/code> instances and <code>Program<\/code> instances are both <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Symbol\/dispose\"><code>Disposable<\/code> objects<\/a>.\nWhen we ask to create them, TypeScript allocates memory and does book-keeping to make sure they stick around between the Go and JavaScript runtimes;\nhowever, when we are done with them, we can&#8217;t just let the garbage collector deal with them or else we&#8217;ll leak on the Go side.\nInstead, we have to do one of the following:<\/p>\n<ul>\n<li>manually dispose of them with explicit method calls (e.g. <code>api.close()<\/code>, <code>program.dispose()<\/code>, or <code>api[Symbol.dispose]()<\/code>), or<\/li>\n<li>automatically dispose of them when they go out of scope by declaring them with the <code>using<\/code> keyword.<\/li>\n<\/ul>\n<p>After a program is disposed, we won&#8217;t be able to use it again.<\/p>\n<h3 id=\"snapshots\">Snapshots<\/h3>\n<p>Above, we modeled a straight-line &#8220;batch&#8221; compilation with the API;\nbut lots of workflows with TypeScript are oriented around changes that might occur over time.\nRather than build up the entire world every time we need, TypeScript is able to model transitions in state with new file updates &#8211; either on disk or as a user types.<\/p>\n<p>Core to the API is the concept of a <em>snapshot<\/em>.\nA snapshot is a version of all the projects and programs at a point in time.\nWe can always create a fresh snapshot with all the information we need with <code>api.createSnapshot<\/code>, but we can also derive a new snapshot from a prior one with the <code>snapshot.update(\/*...*\/)<\/code>.\nThis can often save a lot of work, both in sending over all the original information and having the compiler rebuild the world.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import { ScriptTarget } from \"typescript\/ast\";\r\nimport { createFileSystemLayer, createFileSystemWithLib } from \"typescript\/fs\";\r\nimport { API } from \"typescript\/sync\";\r\nimport { resolve } from \"node:path\";\r\n\r\nconst fileName = resolve(\"snapshot-example.ts\");\r\n\r\nusing api = new API();\r\nusing before = api.createSnapshot({\r\n    fileSystem: createFileSystemWithLib([\r\n        [fileName, 'export const answer: number = \"forty-two\";'],\r\n    ]),\r\n    createPrograms: [\r\n        {\r\n            rootFiles: [fileName],\r\n            compilerOptions: {\r\n                strict: true,\r\n                noEmit: true,\r\n                target: ScriptTarget.ES2022,\r\n            },\r\n        },\r\n    ],\r\n});\r\n\r\nusing beforeProgram = before.operation.createdPrograms[0];\r\nconsole.log(\"before:\", beforeProgram.getSemanticDiagnostics().length);\r\n\r\nusing after = before.update({\r\n    fileSystem: createFileSystemLayer([\r\n        [fileName, \"export const answer: number = 42;\"],\r\n    ]),\r\n    ensurePrograms: [beforeProgram.id],\r\n});\r\n\r\nusing afterProgram = after.getProgram(beforeProgram.id);\r\nif (!afterProgram) {\r\n    throw new Error(\"The updated program was not found.\");\r\n}\r\n\r\nconsole.log(\"after:\", afterProgram.getSemanticDiagnostics().length);\r\nconsole.log(\"before again:\", beforeProgram.getSemanticDiagnostics().length);\r\n\r\n\/\/ Outputs:\r\n\/\/  before: 1\r\n\/\/  after: 0\r\n\/\/  before again: 1\r\n<\/code><\/pre>\n<p>We&#8217;ll come back to those file system APIs in a bit.<\/p>\n<p>One thing to notice here is that we were able to start with an original snapshot named <code>before<\/code> and derive a new snapshot after making a change called <code>after<\/code>.\nSnapshots can contain <code>Program<\/code> objects (and <code>Project<\/code>s) which have <code>id<\/code>s that persist between snapshot changes.\nWe used <code>ensurePrograms<\/code> to specify the <code>Program<\/code>s which we care to observe updates on in the new snapshot (the current default is lazier and allows you to stack <code>update()<\/code> calls without forcing updates to <code>Program<\/code>s).<\/p>\n<p>Notice that even after calling <code>update<\/code>, we&#8217;re able to use information from the prior snapshot.\nFor example, we can still ask for diagnostics on both <code>beforeProgram<\/code> and <code>afterProgram<\/code>.\nThat said, make sure you don&#8217;t mix and match objects derived from one snapshot&#8217;s program, project, or checker.<\/p>\n<p>Snapshots are <code>Disposable<\/code>s like our other types above, so we&#8217;ll need to either manually <code>dispose()<\/code> them or create a local binding for them with <code>using<\/code> declarations.\nAfter a <code>Snapshot<\/code> is disposed, we can&#8217;t use it again.<\/p>\n<h3 id=\"file-system-apis\">File System APIs<\/h3>\n<p>By default, TypeScript&#8217;s APIs will operate over the host file system.\nThat means that it will hit files &#8220;on disk&#8221; unless we say otherwise.<\/p>\n<table>\n<thead>\n<tr>\n<th>Function<\/th>\n<th>Behavior<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>createFileSystem(files)<\/code><\/td>\n<td>Defines a complete file system. Unlisted files are absent, unless explicitly mounted.<\/td>\n<\/tr>\n<tr>\n<td><code>createFileSystemWithLib(files)<\/code><\/td>\n<td>Defines a complete file system and mounts the compiler&#8217;s default library directory read-only.<\/td>\n<\/tr>\n<tr>\n<td><code>createFileSystemLayer(files)<\/code><\/td>\n<td>Overrides selected files while falling back to the base snapshot&#8217;s file system, or the host file system.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In our earlier example, we created a (partial) virtual file system with <code>createFileSystemWithLib<\/code> and specified only the file in our program that we cared about.\nWhen we wanted to make an update, we were able to just use <code>createFileSystemLayer<\/code> for only the files that changed, and other files (like <code>lib.d.ts<\/code> and anything else) continued to resolve through the base file system layer that we made in our initial snapshot.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>\/\/ ...\r\n\r\nusing snapshot = api.createSnapshot({\r\n    fileSystem: createFileSystemWithLib([\r\n        [\r\n            mainFile,\r\n            [\r\n                'import { greeting } from \".\/generated.js\";',\r\n                \"export const message: string = greeting;\",\r\n            ].join(\"\\n\"),\r\n        ],\r\n        [generatedFile, 'export const greeting = \"Hello from memory!\";'],\r\n    ]),\r\n    createPrograms: [\r\n        {\r\n            rootFiles: [mainFile],\r\n            compilerOptions: {\r\n                strict: true,\r\n                module: ModuleKind.ESNext,\r\n                moduleResolution: ModuleResolutionKind.Bundler,\r\n                target: ScriptTarget.ES2022,\r\n            },\r\n        },\r\n    ],\r\n});\r\n\r\nusing program = snapshot.operation.createdPrograms[0];\r\n\r\n\/\/ ...\r\n\/\/ Get emit without writing files to any file system.\r\nconst emitResult = program.emitToString();\r\n<\/code><\/pre>\n<p>There are some ways to control how files are observed over these layers.\nFor example, <code>removedPaths<\/code> can block out requests from the underlying system.<\/p>\n<p>If you need to provide some level of file watching, that currently needs to be done separately.\nFile creations\/deletions\/modifications need to be provided via the <code>fileNotifications<\/code> option in <code>snapshot.update()<\/code>.\nAny modifications that occur that aren&#8217;t in the <em>host<\/em> file system need to be provided with another file system layer.<\/p>\n<h3 id=\"content-mappers\">Content Mappers<\/h3>\n<p>TypeScript has long had powerful checking and tooling for TypeScript and JavaScript code;\nhowever, lots of developers use specialized file types for writing out their components.\nFor example, Vue.js has regions of HTML, JavaScript, and CSS all within a single <code>.vue<\/code> file, along with embedded regions for JavaScript in that HTML.\nThe same is true for libraries like Astro, Ember, Svelte, and others &#8211; these frameworks follow a similar way of declaring their components.\nAt some point, a project called Volar emerged to provide TypeScript tooling for these single-file component formats to provide a seamless development experience in the editor.\nVolar surfaces errors, code completions, navigation, and more by using TypeScript&#8217;s language services, and has been able to extend its capabilities to other formats, such as MDX files.<\/p>\n<p>Unfortunately, one of the challenges with Volar was that TypeScript lacked some of the APIs to easily provide a cohesive experience.\nFor example, while Volar&#8217;s model shined for editor support, command-line type-checkers for these other file formats could not really use Volar because they integrate with completely different APIs from TypeScript.\nAnother issue was the fact that Volar either had to embed TypeScript as a subcomponent and completely take over the editor experience, or it had to use awkward workarounds to integrate with the existing TypeScript tooling given limitations in our APIs.\nWith TypeScript 7.0, we took an opportunity to rethink how the toolset could better support formats that embed JavaScript and TypeScript code.\nIn fact, with TypeScript 7.1, Volar&#8217;s core model is now a first-class citizen.<\/p>\n<p>TypeScript 7.1 introduces support for a new plugin point called <em>content mappers<\/em>.\nA content mapper can be registered with a specific file extension, and is able to produce a virtual representation of a file for TypeScript to see.\nThis representation also has regions that map back to the original file, typically in the regions that contain the corresponding JavaScript or TypeScript code.\nThat allows TypeScript to provide more accurate error messages and spans, and provide tooling for these embedded regions.<\/p>\n<p>To use a content mapper, you&#8217;ll need to register it with a specific set of extensions in your project&#8217;s <code>tsconfig.json<\/code>.\nFor example, if we installed a package called <code>@vue\/content-mapper<\/code> (which is <em>not<\/em> currently on npm), we could include it in our <code>tsconfig.json<\/code> as follows:<\/p>\n<pre class=\"prettyprint language-json\" style=\"padding: 10px; border-radius: 10px;\"><code>{\r\n  \"compilerOptions\": {\r\n    \/\/ ...\r\n  },\r\n  \"contentMappers\": [\r\n    {\r\n      \"package\": \"@vue\/content-mapper\",\r\n      \"extensions\": [\".vue\"],\r\n      \"options\": {\r\n        \"target\": 3.5\r\n      }\r\n    }\r\n  ]\r\n}\r\n<\/code><\/pre>\n<p>Whenever a file is included in the program &#8211; whether that&#8217;s via <code>files<\/code>\/<code>include<\/code> in your <code>tsconfig.json<\/code>, or through an <code>import<\/code>, TypeScript will check for registered content mappers and request content and mappings for that file.\nWe can then run directly from the command line.<\/p>\n<pre class=\"prettyprint language-sh\" style=\"padding: 10px; border-radius: 10px;\"><code>tsc --runExternalCode\r\n<\/code><\/pre>\n<p>Note the <code>--runExternalCode<\/code> flag, which is required to allow TypeScript to execute content mappers.\nContent mappers are effectively arbitrary executables that TypeScript dispatches to, so the <code>--runExternalCode<\/code> flag makes that explicit.<\/p>\n<p>In editors like VS Code, TypeScript 7.1 &#8220;just works&#8221; with content mappers, though it requires both workspace trust and content mapper permissions to be granted.\nIn our VS Code extension, you&#8217;ll have the power to also disable this entirely by configuring the new <code>js\/ts.contentMappers.enabled<\/code> setting.<\/p>\n<p>Content mappers have already been prototyped or implemented for various libraries and frameworks, including:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/withastro\/astro\/pull\/17835\">Astro<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/remcohaszing\/css-modules-content-mapper\">CSS Modules<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/NullVoxPopuli\/ember-content-mapper\/\">Ember<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/remcohaszing\/mdx-content-mapper\">MDX<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/sveltejs\/language-tools\/pull\/3111\">Svelte<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/vuejs\/language-tools\/pull\/6170\">Vue<\/a><\/li>\n<\/ul>\n<p>We even have <a href=\"https:\/\/github.com\/DanielRosenwasser\/content-mapper-sample\">an example content mapper for HTML files<\/a> supporting <code>&lt;script&gt;<\/code> tags and event handler attributes.<\/p>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4712\">see the write-up of content mappers on the implementing pull request<\/a>.<\/p>\n<h3 id=\"more-on-the-api\">More on the API<\/h3>\n<p>We&#8217;ll have more examples of our API in the near future, but we&#8217;re working with partner teams to ensure TypeScript 7.1&#8217;s API is both ergonomic and provides the appropriate performance for real-world usage.\nFeel free to give us some feedback on what works and doesn&#8217;t work for you!<\/p>\n<h2 id=\"optimizations\">Optimizations<\/h2>\n<p>With our last release, we said that TypeScript 7 often achieved somewhere around 10x the performance of TypeScript 6.\nWhile we&#8217;re proud of that, TypeScript 7.1 brings a ton of new optimizations to reduce memory pressure and speed up builds.\nAmong them are:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4240\">Inline <code>GetCombinedNodeFlags<\/code> and <code>GetCombinedModifierFlags<\/code> Bodies<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4313\">Use Balanced Import Affinity When Assigning Files to Type Checkers<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4329\">Optimize Representations of Checker-Specific Side-Tables<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4399\">Improved Program Reuse Under Single-File Changes<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4604\">Prevent Unnecessary Diagnostic Refreshes on Irrelevant Watch Events<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4658\">Fix Build-Mode Setup Stall on Large Solutions<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4687\">Faster Union Type Construction<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4731\">Lazily Collect Source File Identifiers<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4711\">Fast Path for Assignment Narrowing on Unions<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4781\">Fast Path for Equality and <code>switch<\/code>\/<code>case<\/code> Narrowing on Unions<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4744\">Reorganize AST to Prevent Duplicate Fields<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4764\">Remove Unused Classifiable-Name Tracking<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4765\">Fix Quadratic Slowdown When Renaming Files with Duplicate Unresolved Imports<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4776\">Remove Easily-Removable Wasted Work in Parse\/Bind<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4784\">Build Checker Cache Keys in an Inline Buffer with One-Shot Hashing<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4785\">Skip Speculative Expression Parsing in Async-Arrow Lookahead<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4788\">Embed Zero-Size Marker Bases First in Generated AST Structs<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/typescript-go\/pull\/4798\">Avoid Temporary Composite-Mapper Allocations<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/63934\">Optimize LSP Discriminated-Union Decoding<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/63969\">Avoid Cloning Cached Declaration Types After Truncation<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/63977\">Avoid Allocations When Checking Project-Reference Declaration Directories<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/63998\">Reduce Path-Mapping Cache Memory Usage for Projects with Many Paths<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64194\">Cap Template-Literal Type Size to Avoid Unbounded Growth<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64206\">Fix Performance of Nested Generator <code>all<\/code> Calls<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64220\">Schedule <code>tsc -b<\/code> Projects by Dependency Depth<\/a> \/ <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64615\">Restore Dependency-Depth Build Scheduling<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64305\">Avoid Duplicate Symbol-Link Lookup in <code>GetNameTypeOfSymbol<\/code><\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64306\">Preallocate Instantiated Symbol Tables<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64402\">Lazily Allocate the Diagnostic <code>keyToMessage<\/code> Map<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64469\">Index Re-Exporting Modules for Declaration Emit<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64553\">Cache Inferences Made from Type Arguments<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64649\">Cache One Node Builder per Emit Resolver<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64711\">Dense Link Stores<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64739\">Shrink <code>ValueSymbolLinks<\/code> by 16 Bytes<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64648\">Cache <code>getSimplifiedConditionalType<\/code> Results<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64773\">Replace <code>nodeData<\/code> Interface with Generated AST Accessors<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64774\">Compact Checker Type Metadata<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64793\">Batch Allocations of Common Checker Types<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64794\">Presize Checker Type-List Cache Keys<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64795\">Avoid Allocating Normalized Types on Interning Cache Hits<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64796\">Compact Type Mappers and Coallocate Inference Mapper Storage<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64797\">Move Cold Value-Symbol Links Out of Hot Records<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64798\">Recover Concrete AST Nodes from Their Embedded Headers<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64799\">Keep Optional Symbol Tables Out of Hot Symbol Records<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64800\">Move Optional Structured-Type Shape into Cold Storage<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64801\">Keep Optional Type-Node and Signature State Out of Hot Records<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64802\">Bound Arena Retention by Bytes Instead of Object Count<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64803\">Use Paged Indexes for Type-Node and Signature Caches<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64804\">Reuse Ordered Property Counts During Intersection Reduction<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64551\">Add Fast Path <code>compareNodes<\/code> for Shared Parents<\/a><\/li>\n<\/ul>\n<p>Here&#8217;s how these improvements translate into real-world performance gains using the default of 4 type-checker threads and under <code>--noEmit<\/code>:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2026\/10\/ts71-beta-wall-compare-1.png\" alt=\"Performance of TypeScript 7.1 Beta, as described by table below\" \/>\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2026\/10\/ts71-beta-mem-compare-1.png\" alt=\"Memory Usage of TypeScript 7.1 Beta, as described by table below\" \/><\/p>\n<table>\n<thead>\n<tr>\n<th>Codebase<\/th>\n<th style=\"text-align: right;\">TypeScript 7.0<\/th>\n<th style=\"text-align: right;\">TypeScript 7.1 Beta<\/th>\n<th style=\"text-align: right;\">Speedup<\/th>\n<th style=\"text-align: right;\">Time Reduction<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>bluesky<\/td>\n<td style=\"text-align: right;\">4.48s<\/td>\n<td style=\"text-align: right;\">3.89s<\/td>\n<td style=\"text-align: right;\">1.2x<\/td>\n<td style=\"text-align: right;\">13.2%<\/td>\n<\/tr>\n<tr>\n<td>mui-docs<\/td>\n<td style=\"text-align: right;\">22.2s<\/td>\n<td style=\"text-align: right;\">11.9s<\/td>\n<td style=\"text-align: right;\">1.9x<\/td>\n<td style=\"text-align: right;\">46.6%<\/td>\n<\/tr>\n<tr>\n<td>sentry<\/td>\n<td style=\"text-align: right;\">19.6s<\/td>\n<td style=\"text-align: right;\">15.1s<\/td>\n<td style=\"text-align: right;\">1.3x<\/td>\n<td style=\"text-align: right;\">22.8%<\/td>\n<\/tr>\n<tr>\n<td>t3code-server<\/td>\n<td style=\"text-align: right;\">26.5s<\/td>\n<td style=\"text-align: right;\">19.1s<\/td>\n<td style=\"text-align: right;\">1.4x<\/td>\n<td style=\"text-align: right;\">28.2%<\/td>\n<\/tr>\n<tr>\n<td>vscode<\/td>\n<td style=\"text-align: right;\">21.6s<\/td>\n<td style=\"text-align: right;\">17.7s<\/td>\n<td style=\"text-align: right;\">1.2x<\/td>\n<td style=\"text-align: right;\">17.7%<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<table>\n<thead>\n<tr>\n<th>Codebase<\/th>\n<th style=\"text-align: right;\">TypeScript 7.0<\/th>\n<th style=\"text-align: right;\">TypeScript 7.1 Beta<\/th>\n<th style=\"text-align: right;\">Reduction<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>bluesky<\/td>\n<td style=\"text-align: right;\">2,017 MiB<\/td>\n<td style=\"text-align: right;\">1,698 MiB<\/td>\n<td style=\"text-align: right;\">15.8%<\/td>\n<\/tr>\n<tr>\n<td>mui-docs<\/td>\n<td style=\"text-align: right;\">8,093 MiB<\/td>\n<td style=\"text-align: right;\">4,079 MiB<\/td>\n<td style=\"text-align: right;\">49.6%<\/td>\n<\/tr>\n<tr>\n<td>sentry<\/td>\n<td style=\"text-align: right;\">6,587 MiB<\/td>\n<td style=\"text-align: right;\">5,216 MiB<\/td>\n<td style=\"text-align: right;\">20.8%<\/td>\n<\/tr>\n<tr>\n<td>t3code-server<\/td>\n<td style=\"text-align: right;\">6,894 MiB<\/td>\n<td style=\"text-align: right;\">5,197 MiB<\/td>\n<td style=\"text-align: right;\">24.6%<\/td>\n<\/tr>\n<tr>\n<td>vscode<\/td>\n<td style=\"text-align: right;\">8,387 MiB<\/td>\n<td style=\"text-align: right;\">6,943 MiB<\/td>\n<td style=\"text-align: right;\">17.2%<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"notable-behavioral-changes\">Notable Behavioral Changes<\/h2>\n<p>This section highlights a set of noteworthy changes that should be acknowledged and understood as part of any upgrade.\nSometimes it will highlight deprecations, removals, and new restrictions.\nIt can also contain bug fixes that are functionally improvements, but which can also affect an existing build by introducing new errors.<\/p>\n<h3 id=\"libdts\"><code>lib.d.ts<\/code><\/h3>\n<p>Types generated for the DOM may have an impact on type-checking your codebase.\nFor more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/63702\">see linked issues related to DOM and <code>lib.d.ts<\/code> updates for this version of TypeScript<\/a>.<\/p>\n<h3 id=\"stronger-checks-when-using-distributive-type-parameters\">Stronger Checks When Using Distributive Type Parameters<\/h3>\n<p>In TypeScript, a conditional type which evaluates against a type variable (e.g., <code>T<\/code> in <code>T extends Whatever ? TrueType : FalseType<\/code>) will distribute over union types when they are supplied in place of that type variable.\nFor example:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>type Foo&lt;T&gt; = T extends \"a\" | \"b\" | \"c\" ? { known: T } : { unknown: T };\r\n\r\n\/\/ { known: \"a\" } | { known: \"b\" } | { unknown: \"x\" } | { unknown: \"y\" }\r\ntype Bar = Foo&lt;\"a\" | \"b\" | \"x\" | \"y\"&gt;;\r\n<\/code><\/pre>\n<p>Here, <code>T<\/code> is a type parameter, and the string literal types <code>\"a\"<\/code>, <code>\"b\"<\/code>, <code>\"x\"<\/code>, and <code>\"y\"<\/code> are each individually evaluated against the type on the right side of the <code>extends<\/code>.\nThe appropriate branch is instantiated for each member of the union, and the resulting types are then unioned together for the type of <code>Bar<\/code>.<\/p>\n<p>While in each branch of the conditional type above we referred to <code>T<\/code>, that is not <em>quite<\/em> the same <code>T<\/code> as the original type parameter.\nWhen distributing, <code>T<\/code> will represent a more specific subset of the original union type.\nHowever, previous versions of TypeScript did not distinguish the two.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>type Show&lt;A extends number, B extends A&gt; = `${B} extends ${A}`;\r\n\r\ntype Issue&lt;A extends number, B extends A&gt; =\r\n    A extends B ?\r\n        never :\r\n        Show&lt;A, B&gt;; \/\/ We shouldn't be allowed to write this branch!\r\n<\/code><\/pre>\n<p>In the type <code>Issue<\/code>, we wrote out <code>Show&lt;A, B&gt;<\/code> in the false branch, and we&#8217;ll show why that shouldn&#8217;t be allowed.<\/p>\n<p>The <code>Show<\/code> type ensures that its second type parameter is a subtype of the first.\nUnder TypeScript 7.0 and prior, that seemed true &#8211; the <code>Issue<\/code> type declares that <code>B extends A<\/code>, so why wouldn&#8217;t that be the case?\nWell distribution throws a wrench in that assumption.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>\/\/ Forms the string literal type `\"0 extends 1\"`\r\ntype UhOh = Issue&lt;0 | 1, 0&gt;;\r\n<\/code><\/pre>\n<p>Again, the problem is that while a literal type like <code>0<\/code> is a subtype of the union <code>0 | 1<\/code> as a whole, cracking the union apart in each branch really leaves us with distinct types that could be unrelated.\nYou can reframe this in a different way: a <code>Cat<\/code> might be a subtype of <code>Animal<\/code>, but it certainly won&#8217;t be a subtype of every type of <code>Animal<\/code>.<\/p>\n<p>TypeScript 7.1 is stricter about this.\nIn each branch, you can effectively think of <code>T<\/code> being a new type parameter that is a subtype of the original, but won&#8217;t have any relation with other types constrained to the original type parameter.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>type Show&lt;A extends number, B extends A&gt; = `${B} extends ${A}`;\r\n\r\ntype Issue&lt;A extends number, B extends A&gt; =\r\n    A extends B ?\r\n        never :\r\n        Show&lt;A, B&gt;;\r\n\/\/              ~\r\n\/\/ error!\r\n\/\/ Type 'B' does not satisfy the constraint 'A'.\r\n\/\/   'B' is only assignable to the non-distributed 'A', but 'A' has been distributed here.\r\n<\/code><\/pre>\n<p>Code that encounters this may need to be modified, either removing the original constraint if it&#8217;s unnecessary or adding additional conditional type checks to satisfy required constraints of other types.<\/p>\n<p>For more information, see <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/63708\">the reporting issue<\/a> along with <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/64237\">the pull request that introduced this change<\/a>.<\/p>\n<h2 id=\"whats-next\">What&#8217;s Next?<\/h2>\n<p>Coming up next, we&#8217;ll be focused on addressing speed and stability improvements, including feedback on new features and work introduced in TypeScript 7.1 Beta.\nThat will be followed by a Release Candidate in about a month from now, followed by a final release shortly thereafter.<\/p>\n<p>With TypeScript 7.1, we&#8217;re hoping to make sure that the API story really comes together and that we can deliver on even better speed with a leaner memory footprint.\nSo give it a try today, let us know what you think, and happy hacking!<\/p>\n<p>&#8211; Daniel Rosenwasser and the TypeScript Team<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re excited to announce the beta release of TypeScript 7.1! npm install -D typescript@beta Let&#8217;s take a look at what&#8217;s new in TypeScript 7.1! Support for Import Attributes in Ambient Modules Import attributes are metadata that are attached to import statements. Typically, they&#8217;re meant to instruct runtimes and bundlers on how to interpret the [&hellip;]<\/p>\n","protected":false},"author":381,"featured_media":5475,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5473","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-typescript"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re excited to announce the beta release of TypeScript 7.1! npm install -D typescript@beta Let&#8217;s take a look at what&#8217;s new in TypeScript 7.1! Support for Import Attributes in Ambient Modules Import attributes are metadata that are attached to import statements. Typically, they&#8217;re meant to instruct runtimes and bundlers on how to interpret the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/5473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/users\/381"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/comments?post=5473"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/5473\/revisions"}],"predecessor-version":[{"id":5476,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/5473\/revisions\/5476"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/media\/5475"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/media?parent=5473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=5473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=5473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}