{"id":4472,"date":"2024-10-09T12:59:51","date_gmt":"2024-10-09T20:59:51","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=4472"},"modified":"2024-10-09T12:59:51","modified_gmt":"2024-10-09T20:59:51","slug":"announcing-typescript-5-7-beta","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-7-beta\/","title":{"rendered":"Announcing TypeScript 5.7 Beta"},"content":{"rendered":"<p>Today we are announcing the availability of TypeScript 5.7 Beta.<\/p>\n<p>To get started using the beta, you can get it through npm with the following command:<\/p>\n<pre class=\"lang:default decode:true\" 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 5.7!<\/p>\n<h2 id=\"checks-for-never-initialized-variables\">Checks for Never-Initialized Variables<\/h2>\n<p>For a long time, TypeScript has been able to catch issues when a variable has not yet been initialized in all prior branches.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>let result: number\r\nif (someCondition()) {\r\n    result = doSomeWork();\r\n}\r\nelse {\r\n    let temporaryWork = doSomeWork();\r\n    temporaryWork *= 2;\r\n    \/\/ forgot to assign to 'result'\r\n}\r\n\r\nconsole.log(result); \/\/ error: Variable 'result' is used before being assigned.\r\n<\/code><\/pre>\n<p>Unfortunately, there are some places where this analysis doesn&#8217;t work.\nFor example, if the variable is accessed in a separate function, the type system doesn&#8217;t know when the function will be called, and instead takes an &quot;optimistic&quot; view that the variable will be initialized.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>function foo() {\r\n    let result: number\r\n    if (someCondition()) {\r\n        result = doSomeWork();\r\n    }\r\n    else {\r\n        let temporaryWork = doSomeWork();\r\n        temporaryWork *= 2;\r\n        \/\/ forgot to assign to 'result'\r\n    }\r\n\r\n    printResult();\r\n\r\n    function printResult() {\r\n        console.log(result); \/\/ no error here.\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>While TypeScript 5.7 is still lenient on variables that have <em>possibly<\/em> been initialized, the type system is able to report errors when variables have <em>never<\/em> been initialized at all.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>function foo() {\r\n    let result: number\r\n    \r\n    \/\/ do work, but forget to assign to 'result'\r\n\r\n    function printResult() {\r\n        console.log(result); \/\/ error: Variable 'result' is used before being assigned.\r\n    }\r\n}\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/55887\">This change<\/a> was contributed thanks to the work of GitHub user <a href=\"https:\/\/github.com\/Zzzen\">Zzzen<\/a>!<\/p>\n<h2 id=\"path-rewriting-for-relative-paths\">Path Rewriting for Relative Paths<\/h2>\n<p>There are several tools and runtimes that allow you to run TypeScript code &quot;in-place&quot;, meaning they do not require a build step which generates output JavaScript files.\nFor example, ts-node, tsx, Deno, and Bun all support running <code>.ts<\/code> files directly.\nMore recently, Node.js has been investigating such support with <code>--experimental-transform-types<\/code> and <code>--experimental-strip-types<\/code>.\nThis is extremely convenient because it allows us to iterate faster without worrying about re-running a build task.<\/p>\n<p>There is some complexity to be aware of when using these modes though.\nTo be maximally compatible with all these tools, a TypeScript file that&#8217;s imported &quot;in-place&quot; <strong>must<\/strong> be imported with the appropriate TypeScript extension at runtime.\nFor example, to import a file called <code>foo.ts<\/code>, we have to write the following in Node&#8217;s new experimental support:<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ main.ts\r\n\r\nimport * as foo from &quot;.\/foo.ts&quot;; \/\/ &lt;- we need foo.ts here, not foo.js\r\n<\/code><\/pre>\n<p>Typically, TypeScript would issue an error if we did this, because it expects us to import <em>the output file<\/em>.\nBecause some tools do allow <code>.ts<\/code> imports, TypeScript has supported this import style with an option called <code>--allowImportingTsExtensions<\/code> for a while now.\nThis works fine, but what happens if we need to actually generate <code>.js<\/code> files out of these <code>.ts<\/code> files?\nThis is a requirement for library authors who will need to be able to distribute just <code>.js<\/code> files, but up until now TypeScript has avoided rewriting any paths.<\/p>\n<p>To support this scenario, we&#8217;ve added a new compiler option called <code>--rewriteRelativeImportExtensions<\/code>.\nWhen an import path is <em>relative<\/em> (starts with <code>.\/<\/code> or <code>..\/<\/code>), ends in a TypeScript extension (<code>.ts<\/code>, <code>.tsx<\/code>, <code>.mts<\/code>, <code>.cts<\/code>), and is a non-declaration file, the compiler will rewrite the path to the corresponding JavaScript extension (<code>.js<\/code>, <code>.jsx<\/code>, <code>.mjs<\/code>, <code>.cjs<\/code>).<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ Under --rewriteRelativeImportExtensions...\r\n\r\n\/\/ these will be rewritten.\r\nimport * as foo from &quot;.\/foo.ts&quot;;\r\nimport * as bar from &quot;..\/someFolder\/bar.mts&quot;;\r\n\r\n\/\/ these will NOT be rewritten in any way.\r\nimport * as a from &quot;.\/foo&quot;;\r\nimport * as b from &quot;some-package\/file.ts&quot;;\r\nimport * as c from &quot;@some-scope\/some-package\/file.ts&quot;;\r\nimport * as d from &quot;#\/file.ts&quot;;\r\nimport * as e from &quot;.\/file.js&quot;;\r\n<\/code><\/pre>\n<p>This allows us to write TypeScript code that can be run in-place and then compiled into JavaScript when we&#8217;re ready.<\/p>\n<p>Now, we noted that TypeScript generally avoided rewriting paths.\nThere are several reasons for this, but the most obvious one is dynamic imports.\nIf a developer writes the following, it&#8217;s not trivial to handle the path that <code>import<\/code> receives.\nIn fact, it&#8217;s impossible to override the behavior of <code>import<\/code> within any dependencies.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>function getPath() {\r\n    if (Math.random() &lt; 0.5) {\r\n        return &quot;.\/foo.ts&quot;;\r\n    }\r\n    else {\r\n        return &quot;.\/foo.js&quot;;\r\n    }\r\n}\r\n\r\nlet myImport = await import(getPath());\r\n<\/code><\/pre>\n<p>Another issue is that (as we saw above) only <em>relative<\/em> paths are rewritten, and they are written &quot;naively&quot;.\nThis means that any path that relies on TypeScript&#8217;s <code>baseUrl<\/code> and <code>paths<\/code> will not get rewritten:<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ tsconfig.json\r\n\r\n{\r\n    &quot;compilerOptions&quot;: {\r\n        &quot;module&quot;: &quot;nodenext&quot;,\r\n        \/\/ ...\r\n        &quot;paths&quot;: {\r\n            &quot;@\/*&quot;: [&quot;.\/src\/*&quot;]\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ Won't be transformed, won't work.\r\nimport * as utilities from &quot;@\/utilities.ts&quot;;\r\n<\/code><\/pre>\n<p>Nor will any path that might resolve through the <a href=\"https:\/\/nodejs.org\/api\/packages.html#exports\"><code>exports<\/code><\/a> and <a href=\"https:\/\/nodejs.org\/api\/packages.html#imports\"><code>imports<\/code><\/a> fields of a <code>package.json<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ package.json\r\n{\r\n    &quot;name&quot;: &quot;my-package&quot;,\r\n    &quot;imports&quot;: {\r\n        &quot;#root\/*&quot;: &quot;.\/dist\/*&quot;\r\n    }\r\n}\r\n<\/code><\/pre>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ Won't be transformed, won't work.\r\nimport * as utilities from &quot;#root\/utilities.ts&quot;;\r\n<\/code><\/pre>\n<p>As a result, if you&#8217;ve been using a workspace-style layout with multiple packages referencing each other, you might need to use <a href=\"https:\/\/nodejs.org\/api\/packages.html#conditional-exports\">conditional exports<\/a> with <a href=\"https:\/\/nodejs.org\/api\/packages.html#resolving-user-conditions\">scoped custom conditions<\/a> to make this work:<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ my-package\/package.json\r\n\r\n{\r\n    &quot;name&quot;: &quot;my-package&quot;,\r\n    &quot;exports&quot;: {\r\n        &quot;.&quot;: {\r\n            &quot;@my-package\/development&quot;: &quot;.\/src\/index.ts&quot;,\r\n            &quot;import&quot;: &quot;.\/lib\/index.js&quot;\r\n        },\r\n        &quot;.\/*&quot;: {\r\n            &quot;@my-package\/development&quot;: &quot;.\/src\/*.ts&quot;,\r\n            &quot;import&quot;: &quot;.\/lib\/*.js&quot;\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Any time you want to import the <code>.ts<\/code> files, you can run it with <code>node --conditions=@my-package\/development<\/code>.<\/p>\n<p>Note the &quot;namespace&quot; or &quot;scope&quot; we used for the condition <code>@my-package\/development<\/code>.\nThis is a bit of a makeshift solution to avoid conflicts from dependencies that might also use the <code>development<\/code> condition.\nIf everyone ships a <code>development<\/code> in their package, then resolution may try to resolve to a <code>.ts<\/code> file which will not necessarily work.\nThis idea is similar to what&#8217;s described in Colin McDonnell&#8217;s essay <em><a href=\"https:\/\/colinhacks.com\/essays\/live-types-typescript-monorepo#:~:text=custom%20conditions\">Live types in a TypeScript monorepo<\/a><\/em>, along with <a href=\"https:\/\/github.com\/isaacs\/tshy#loading-from-source\">tshy&#8217;s guidance for loading from source<\/a>.<\/p>\n<p>For more specifics on how this feature works, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59767\">read up on the change here<\/a>.<\/p>\n<h2 id=\"support-for---target-es2024-and---lib-es2024\">Support for <code>--target es2024<\/code> and <code>--lib es2024<\/code><\/h2>\n<p>TypeScript 5.7 now supports <code>--target es2024<\/code>, which allows users to target ECMAScript 2024 runtimes.\nThis target primarily enables specifying the new <code>--lib es2024<\/code> which contains many features for <code>SharedArrayBuffer<\/code> and <code>ArrayBuffer<\/code>, <code>Object.groupBy<\/code>, <code>Map.groupBy<\/code>, <code>Promise.withResolvers<\/code>, and more.\nIt also moves <code>Atomics.waitAsync<\/code> from <code>--lib es2022<\/code> to <code>--lib es2024<\/code>.<\/p>\n<p>Note that as part of the changes to <code>SharedArrayBuffer<\/code> and <code>ArrayBuffer<\/code>, the two now diverge a bit.\nTo bridge the gap and preserve the underlying buffer type, all <code>TypedArrays<\/code> (like <code>Uint8Array<\/code> and others) <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59417\">are now also generic<\/a>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>interface Uint8Array&lt;TArrayBuffer extends ArrayBufferLike = ArrayBufferLike&gt; {\r\n    \/\/ ...\r\n}\r\n<\/code><\/pre>\n<p>Each <code>TypedArray<\/code> now contains a type parameter named <code>TArrayBuffer<\/code>, though that type parameter has a default type argument so that we can continue to refer to <code>Int32Array<\/code> without explicitly writing out <code>Int32Array&lt;ArrayBufferLike&gt;<\/code>.<\/p>\n<p>If you encounter any issues as part of this update, you may need to update <code>@types\/node<\/code>.<\/p>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/58573\">This work<\/a> was primarily provided thanks to <a href=\"https:\/\/github.com\/petamoriken\">Kenta Moriuchi<\/a>!<\/p>\n<h2 id=\"searching-ancestor-configuration-files-for-project-ownership\">Searching Ancestor Configuration Files for Project Ownership<\/h2>\n<p>When a TypeScript file is loaded in an editor using TSServer (like Visual Studio or VS Code), the editor will try to find the relevant <code>tsconfig.json<\/code> file that &quot;owns&quot; the file.\nTo do this, it walks up the directory tree from the file being edited, looking for any file named <code>tsconfig.json<\/code>.<\/p>\n<p>Previously, this search would stop at the first <code>tsconfig.json<\/code> file found;\nhowever, imagine a project structure like the following:<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>project\/\r\n\u251c\u2500\u2500 src\/\r\n\u2502   \u251c\u2500\u2500 foo.ts\r\n\u2502   \u251c\u2500\u2500 foo-test.ts\r\n\u2502   \u251c\u2500\u2500 tsconfig.json\r\n\u2502   \u2514\u2500\u2500 tsconfig.test.json\r\n\u2514\u2500\u2500 tsconfig.json\r\n<\/code><\/pre>\n<p>Here, the idea is that <code>src\/tsconfig.json<\/code> is the &quot;main&quot; configuration file for the project, and <code>src\/tsconfig.test.json<\/code> is a configuration file for running tests.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ src\/tsconfig.json\r\n{\r\n    &quot;compilerOptions&quot;: {\r\n        &quot;outDir&quot;: &quot;..\/dist&quot;\r\n    },\r\n    &quot;exclude&quot;: [&quot;**\/*.test.ts&quot;]\r\n}\r\n<\/code><\/pre>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ src\/tsconfig.test.json\r\n{\r\n    &quot;compilerOptions&quot;: {\r\n        &quot;outDir&quot;: &quot;..\/dist\/test&quot;\r\n    },\r\n    &quot;include&quot;: [&quot;**\/*.test.ts&quot;],\r\n    &quot;references&quot;: [\r\n        { &quot;path&quot;: &quot;.\/tsconfig.json&quot; }\r\n    ]\r\n}\r\n<\/code><\/pre>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ tsconfig.json\r\n{\r\n    \/\/ This is a &quot;workspace-style&quot; or &quot;solution-style&quot; tsconfig.\r\n    \/\/ Instead of specifying any files, it just references all the actual projects.\r\n    &quot;files&quot;: [],\r\n    &quot;references&quot;: [\r\n        { &quot;path&quot;: &quot;.\/src\/tsconfig.json&quot; },\r\n        { &quot;path&quot;: &quot;.\/src\/tsconfig.test.json&quot; },\r\n    ]\r\n}\r\n<\/code><\/pre>\n<p>The problem here is that when editing <code>foo-test.ts<\/code>, the editor would find <code>project\/src\/tsconfig.json<\/code> as the &quot;owning&quot; configuration file &#8211; but that&#8217;s not the one we want!\nIf the walk stops at this point, that might not be desirable.\nThe only way to avoid this previously was to rename <code>src\/tsconfig.json<\/code> to something like <code>src\/tsconfig.src.json<\/code>, and then all files would hit the top-level <code>tsconfig.json<\/code> which references every possible project.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>project\/\r\n\u251c\u2500\u2500 src\/\r\n\u2502   \u251c\u2500\u2500 foo.ts\r\n\u2502   \u251c\u2500\u2500 foo-test.ts\r\n\u2502   \u251c\u2500\u2500 tsconfig.src.json\r\n\u2502   \u2514\u2500\u2500 tsconfig.test.json\r\n\u2514\u2500\u2500 tsconfig.json\r\n<\/code><\/pre>\n<p>Instead of forcing developers to do this, TypeScript 5.7 now continues walking up the directory tree to find other appropriate <code>tsconfig.json<\/code> files for editor scenarios.\nThis can provide more flexibility in how projects are organized and how configuration files are structured.<\/p>\n<p>You can get more specifics on the implementation on GitHub <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/57196\">here<\/a> and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59688\">here<\/a>.<\/p>\n<h2 id=\"faster-project-ownership-checks-in-editors-for-composite-projects\">Faster Project Ownership Checks in Editors for Composite Projects<\/h2>\n<p>Imagine a large codebase with the following structure:<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>packages\r\n\u251c\u2500\u2500 graphics\/\r\n\u2502   \u251c\u2500\u2500 tsconfig.json\r\n\u2502   \u2514\u2500\u2500 src\/\r\n\u2502       \u2514\u2500\u2500 ...\r\n\u251c\u2500\u2500 sound\/\r\n\u2502   \u251c\u2500\u2500 tsconfig.json\r\n\u2502   \u2514\u2500\u2500 src\/\r\n\u2502       \u2514\u2500\u2500 ...\r\n\u251c\u2500\u2500 networking\/\r\n\u2502   \u251c\u2500\u2500 tsconfig.json\r\n\u2502   \u2514\u2500\u2500 src\/\r\n\u2502       \u2514\u2500\u2500 ...\r\n\u251c\u2500\u2500 input\/\r\n\u2502   \u251c\u2500\u2500 tsconfig.json\r\n\u2502   \u2514\u2500\u2500 src\/\r\n\u2502       \u2514\u2500\u2500 ...\r\n\u2514\u2500\u2500 app\/\r\n    \u251c\u2500\u2500 tsconfig.json\r\n    \u251c\u2500\u2500 some-script.js\r\n    \u2514\u2500\u2500 src\/\r\n        \u2514\u2500\u2500 ...\r\n<\/code><\/pre>\n<p>Each directory in <code>packages<\/code> is a separate TypeScript project, and the <code>app<\/code> directory is the main project that depends on all the other projects.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ app\/tsconfig.json\r\n{\r\n    &quot;compilerOptions&quot;: {\r\n        \/\/ ...\r\n    },\r\n    &quot;include&quot;: [&quot;src&quot;],\r\n    &quot;references&quot;: [\r\n        { &quot;path&quot;: &quot;..\/graphics\/tsconfig.json&quot; },\r\n        { &quot;path&quot;: &quot;..\/sound\/tsconfig.json&quot; },\r\n        { &quot;path&quot;: &quot;..\/networking\/tsconfig.json&quot; },\r\n        { &quot;path&quot;: &quot;..\/input\/tsconfig.json&quot; }\r\n    ]\r\n}\r\n<\/code><\/pre>\n<p>Now notice we have the file <code>some-script.js<\/code> in the <code>app<\/code> directory.\nWhen we open <code>some-script.js<\/code> in the editor, the TypeScript language service (which also handles the editor experience for JavaScript files!) has to figure out which project the file belongs to so it can apply the right settings.<\/p>\n<p>In this case, the nearest <code>tsconfig.json<\/code> does <em>not<\/em> include <code>some-script.js<\/code>, but TypeScript will proceed to ask &quot;could one of the projects <em>referenced<\/em> by <code>app\/tsconfig.json<\/code> include <code>some-script.js<\/code>?&quot;.\nTo do so, TypeScript would previously load up each project, one-by-one, and stop as soon as it found a project which contained <code>some-script.js<\/code>.\nEven if <code>some-script.js<\/code> isn&#8217;t included in the root set of files, TypeScript would still parse all the files within a project because some of the root set of files can still <em>transitively<\/em> reference <code>some-script.js<\/code>.<\/p>\n<p>What we found over time was that this behavior caused extreme and unpredictable behavior in larger codebases.\nDevelopers would open up stray script files and find themselves waiting for their entire codebase to be opened up.<\/p>\n<p>Thankfully, every project that can be referenced by another (non-workspace) project must enable a flag called <code>composite<\/code>, which enforces a rule that all input source files must be known up-front.\nSo when probing a <code>composite<\/code> project, TypeScript 5.7 will only check if a file belongs to the <em>root set of files<\/em> of that project.\nThis should avoid this common worst-case behavior.<\/p>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59688\">see the change here<\/a>.<\/p>\n<h3 id=\"validated-json-imports-in---module-nodenext\">Validated JSON Imports in <code>--module nodenext<\/code><\/h3>\n<p>When importing from a <code>.json<\/code> file under <code>--module nodenext<\/code>, TypeScript will now enforce certain rules to prevent runtime errors.<\/p>\n<p>For one, an import attribute containing <code>type: &quot;json&quot;<\/code> needs to be present for any JSON file import.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>import myConfig from &quot;.\/myConfig.json&quot;;\r\n\/\/                   ~~~~~~~~~~~~~~~~~\r\n\/\/ \u274c error: Importing a JSON file into an ECMAScript module requires a 'type: &quot;json&quot;' import attribute when 'module' is set to 'NodeNext'.\r\n\r\nimport myConfig from &quot;.\/myConfig.json&quot; with { type: &quot;json&quot; };\r\n\/\/                                          ^^^^^^^^^^^^^^^^\r\n\/\/ \u2705 This is fine because we provided `type: &quot;json&quot;`\r\n<\/code><\/pre>\n<p>On top of this validation, TypeScript will not generate &quot;named&quot; exports, and the contents of a JSON import will only be accessible via a default.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ \u2705 This is okay:\r\nimport myConfigA from &quot;.\/myConfig.json&quot; with { type: &quot;json&quot; };\r\nlet version = myConfigA.version;\r\n\r\n\/\/\/\/\/\/\/\/\/\/\/\r\n\r\nimport * as myConfigB from &quot;.\/myConfig.json&quot; with { type: &quot;json&quot; };\r\n\r\n\/\/ \u274c This is not:\r\nlet version = myConfig.version;\r\n\r\n\/\/ \u2705 This is okay:\r\nlet version = myConfig.default.version;\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/60019\">See here<\/a> for more information on this change.<\/p>\n<h2 id=\"support-for-v8-compile-caching-in-nodejs\">Support for V8 Compile Caching in Node.js<\/h2>\n<p>Node.js 22 supports <a href=\"https:\/\/github.com\/nodejs\/node\/pull\/54501\">a new API called <code>module.enableCompileCache()<\/code><\/a>.\nThis API allows the runtime to reuse some of the parsing and compilation work done after the first run of a tool.<\/p>\n<p>TypeScript 5.7 now leverages the API so that it can start doing useful work sooner.\nIn some of our own testing, we&#8217;ve witnessed about a 2.5x speed-up in running <code>tsc --version<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>Benchmark 1: node .\/built\/local\/_tsc.js --version (*without* caching)\r\n  Time (mean \u00b1 \u03c3):     122.2 ms \u00b1   1.5 ms    [User: 101.7 ms, System: 13.0 ms]\r\n  Range (min \u2026 max):   119.3 ms \u2026 132.3 ms    200 runs\r\n \r\nBenchmark 2: node .\/built\/local\/tsc.js --version  (*with* caching)\r\n  Time (mean \u00b1 \u03c3):      48.4 ms \u00b1   1.0 ms    [User: 34.0 ms, System: 11.1 ms]\r\n  Range (min \u2026 max):    45.7 ms \u2026  52.8 ms    200 runs\r\n \r\nSummary\r\n  node .\/built\/local\/tsc.js --version ran\r\n    2.52 \u00b1 0.06 times faster than node .\/built\/local\/_tsc.js --version\r\n<\/code><\/pre>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59720\">see the pull request here<\/a>.<\/p>\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\/pull\/60061\">see linked issues related to DOM and <code>lib.d.ts<\/code> updates for this version of TypeScript<\/a>.<\/p>\n<h3 id=\"typedarrays-are-now-generic-over-arraybufferlike\"><code>TypedArray<\/code>s Are Now Generic Over <code>ArrayBufferLike<\/code><\/h3>\n<p>In ECMAScript 2024, <code>SharedArrayBuffer<\/code> and <code>ArrayBuffer<\/code> have types that slightly diverge.\nTo bridge the gap and preserve the underlying buffer type, all <code>TypedArrays<\/code> (like <code>Uint8Array<\/code> and others) <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59417\">are now also generic<\/a>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>interface Uint8Array&lt;TArrayBuffer extends ArrayBufferLike = ArrayBufferLike&gt; {\r\n    \/\/ ...\r\n}\r\n<\/code><\/pre>\n<p>Each <code>TypedArray<\/code> now contains a type parameter named <code>TArrayBuffer<\/code>, though that type parameter has a default type argument so that users can continue to refer to <code>Int32Array<\/code> without explicitly writing out <code>Int32Array&lt;ArrayBufferLike&gt;<\/code>.<\/p>\n<p>If you encounter any issues as part of this update, such as<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>error TS2322: Type 'Buffer' is not assignable to type 'Uint8Array&lt;ArrayBufferLike&gt;'.\r\nerror TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'Uint8Array&lt;ArrayBufferLike&gt;'.\r\nerror TS2345: Argument of type 'ArrayBufferLike' is not assignable to parameter of type 'ArrayBuffer'.\r\nerror TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string | ArrayBufferView | Stream | Iterable&lt;string | ArrayBufferView&gt; | AsyncIterable&lt;string | ArrayBufferView&gt;'.\r\n<\/code><\/pre>\n<p>then you may need to update <code>@types\/node<\/code>.<\/p>\n<p>You can read the <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59417\">specifics about this change on GitHub<\/a>.<\/p>\n<h3 id=\"creating-index-signatures-from-non-literal-method-names-in-classes\">Creating Index Signatures from Non-Literal Method Names in Classes<\/h3>\n<p>TypeScript now has a more consistent behavior for methods in classes when they are declared with non-literal computed property names.\nFor example, in the following:<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>declare const symbolMethodName: symbol;\r\n\r\nexport class A {\r\n    [symbolMethodName]() { return 1 };\r\n}\r\n<\/code><\/pre>\n<p>Previously TypeScript just viewed the class in a way like the following:<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>export class A {\r\n}\r\n<\/code><\/pre>\n<p>In other words, from the type system&#8217;s perspective, <code>[symbolMethodName]<\/code> contributed nothing to the type of <code>A<\/code><\/p>\n<p>TypeScript 5.7 now views the method <code>[symbolMethodName]() {}<\/code> more meaningfully, and generates an index signature.\nAs a result, the code above is interpreted as something like the following code:<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>export class A {\r\n    [x: symbol]: () =&gt; number;\r\n}\r\n<\/code><\/pre>\n<p>This provides behavior that is consistent with properties and methods in object literals.<\/p>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59860\">Read up more on this change here<\/a>.<\/p>\n<h3 id=\"more-implicit-any-errors-on-functions-returning-null-and-undefined\">More Implicit <code>any<\/code> Errors on Functions Returning <code>null<\/code> and <code>undefined<\/code><\/h3>\n<p>When a function expression is contextually typed by a signature returning a generic type, TypeScript now appropriately provides an implicit <code>any<\/code> error under <code>noImplicitAny<\/code>, but outside of <code>strictNullChecks<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"padding: 10px;border-radius: 10px;\"><code>declare var p: Promise&lt;number&gt;;\r\nconst p2 = p.catch(() =&gt; null);\r\n\/\/                 ~~~~~~~~~~\r\n\/\/ error TS7011: Function expression, which lacks return-type annotation, implicitly has an 'any' return type.\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/59661\">See this change for more details<\/a>.<\/p>\n<h2 id=\"whats-next\">What&#8217;s Next?<\/h2>\n<p>At this point, TypeScript 5.7 is what we&#8217;d call &quot;feature-stable&quot;.\nThe focus on TypeScript 5.7 will be bug fixes, polish, and certain low-risk editor features.\nWe&#8217;ll have a release candidate available in a bit over month, followed by a stable release soon after.\nIf you&#8217;re interested in planning around the release, be sure to <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/59905\">keep an eye on our iteration plan<\/a> which has target release dates and more.<\/p>\n<p>As a note: while the beta is a great way to try out the next version of TypeScript, you can also <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\">try a nightly build<\/a> to get the most up-to-date version of TypeScript 5.7 up until our release candidate.\nOur nightlies are well-tested and can even be tested <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=ms-vscode.vscode-typescript-next\">solely in your editor<\/a>.<\/p>\n<p>So please try out the beta or a nightly release today and let us know what you think!<\/p>\n<p>Happy Hacking!<\/p>\n<p>&#8211; Daniel Rosenwasser and the TypeScript Team<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we are announcing the availability of TypeScript 5.7 Beta. To get started using the beta, you can get it through npm with the following command: npm install -D typescript@beta Let&#8217;s take a look at what&#8217;s new in TypeScript 5.7! Checks for Never-Initialized Variables For a long time, TypeScript has been able to catch issues [&hellip;]<\/p>\n","protected":false},"author":381,"featured_media":1797,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4472","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-typescript"],"acf":[],"blog_post_summary":"<p>Today we are announcing the availability of TypeScript 5.7 Beta. To get started using the beta, you can get it through npm with the following command: npm install -D typescript@beta Let&#8217;s take a look at what&#8217;s new in TypeScript 5.7! Checks for Never-Initialized Variables For a long time, TypeScript has been able to catch issues [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/4472","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=4472"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/4472\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/media\/1797"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/media?parent=4472"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=4472"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=4472"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}