{"id":3192,"date":"2021-11-02T14:49:42","date_gmt":"2021-11-02T22:49:42","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=3192"},"modified":"2021-11-02T14:49:42","modified_gmt":"2021-11-02T22:49:42","slug":"announcing-typescript-4-5-rc","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-5-rc\/","title":{"rendered":"Announcing TypeScript 4.5 RC"},"content":{"rendered":"<p>Today we&#8217;re excited to announce our Release Candidate (RC) of TypeScript 4.5! Between now and the stable release of TypeScript 4.5, we expect no further changes apart from critical bug fixes.<\/p>\n<p>To get started using the RC, you can get it\u00a0<a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.TypeScript.MSBuild\" rel=\"nofollow\">through NuGet<\/a>, or use npm with the following command:<\/p>\n<div class=\"highlight highlight-source-shell position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\">npm install typescript@rc<\/pre>\n<\/div>\n<p>You can also get editor support by<\/p>\n<ul>\n<li><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=TypeScriptTeam.TypeScript-45rc\" rel=\"nofollow\">Downloading for Visual Studio 2019\/2017<\/a><\/li>\n<li>Trying\u00a0<a href=\"https:\/\/code.visualstudio.com\/insiders\/\" rel=\"nofollow\">Visual Studio Code Insiders<\/a>\u00a0or following directions for\u00a0<a href=\"https:\/\/code.visualstudio.com\/Docs\/languages\/typescript#_using-newer-typescript-versions\" rel=\"nofollow\">Visual Studio Code<\/a>\u00a0and\u00a0<a href=\"https:\/\/github.com\/Microsoft\/TypeScript-Sublime-Plugin\/#note-using-different-versions-of-typescript\">Sublime Text 3<\/a>.<\/li>\n<\/ul>\n<p>If you&#8217;ve already read\u00a0<a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-5-beta\/\" rel=\"nofollow\">our beta blog post<\/a>, you can\u00a0<a href=\"#beta-delta\">read up on what&#8217;s changed since<\/a>.<\/p>\n<p>Some major highlights of TypeScript 4.5 are:<\/p>\n<ul>\n<li><a href=\"#esm-nodejs\">Experimental Nightly-Only ECMAScript Module Support in Node.js<\/a><\/li>\n<li><a href=\"#lib-node-modules\">Supporting\u00a0<code>lib<\/code>\u00a0from\u00a0<code>node_modules<\/code><\/a><\/li>\n<li><a href=\"#awaited-type\">The\u00a0<code>Awaited<\/code>\u00a0Type and\u00a0<code>Promise<\/code>\u00a0Improvements<\/a><\/li>\n<li><a href=\"#template-string-discriminants\">Template String Types as Discriminants<\/a><\/li>\n<li><a href=\"#module-es2022\"><code>--module es2022<\/code><\/a><\/li>\n<li><a href=\"#tailrec-conditional\">Tail-Recursion Elimination on Conditional Types<\/a><\/li>\n<li><a href=\"#preserve-value-imports\">Disabling Import Elision<\/a><\/li>\n<li><a href=\"#type-on-import-names\"><code>type<\/code>\u00a0Modifiers on Import Names<\/a><\/li>\n<li><a href=\"#private-field-presence-checks\">Private Field Presence Checks<\/a><\/li>\n<li><a href=\"#import-assertions\">Import Assertions<\/a><\/li>\n<li><a href=\"#real-path-sync-native\">Faster Load Time with\u00a0<code>realPathSync.native<\/code><\/a><\/li>\n<li><a href=\"#snippet-completions\">New Snippet Completions<\/a><\/li>\n<li><a href=\"#display-unresolved-types\">Better Editor Support for Unresolved Types<\/a><\/li>\n<li><a href=\"#breaking-changes\">Breaking Changes<\/a><\/li>\n<\/ul>\n<h2 id=\"beta-delta\">What&#8217;s New Since the Beta?<\/h2>\n<p>Since\u00a0<a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-5-beta\" rel=\"nofollow\">our beta release post<\/a>, 4.5 has gone through a few changes.<\/p>\n<p>The biggest change we&#8217;ve made since the beta is that\u00a0<a href=\"#esm-nodejs\">ECMAScript module support for Node.js 12 has been deferred<\/a>\u00a0to a future release, and is now only available as an experimental flag in nightly releases. This was not an easy decision, but our team had a combination of\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/46452\">concerns around ecosystem readiness and general guidance for how\/when to use the feature<\/a>. We felt it would be better to smooth out the user experience instead of releasing something that would ultimately be too frustrating for most people. In the meantime though, you can still use the new support for\u00a0<code>--module nodenext<\/code>\u00a0and\u00a0<code>--moduleResolution nodenext<\/code>\u00a0as experimental features in\u00a0<a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\" rel=\"nofollow\">nightly builds of TypeScript<\/a>. If you try to use these settings in TypeScript 4.5 RC or stable, you&#8217;ll receive an error message directing you to use a nightly build instead.<\/p>\n<p>From the language editing side, we&#8217;ve introduced more snippet completions &#8211;\u00a0<a href=\"#subclass-method-snippets\">specifically, for method implementation and overrides<\/a>.<\/p>\n<p>We&#8217;ve also\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/46209\">addressed a performance regression in\u00a0<code>--build<\/code>\u00a0mode<\/a>\u00a0due to excessive\u00a0<code>realpath<\/code>\u00a0calls for\u00a0<code>package.json<\/code>\u00a0files. This change was made for TypeScript 4.5, but was also back-ported to TypeScript 4.4.4. If this regression blocked you from trying TypeScript 4.4, you should see comparable or better speed in\u00a0<code>--build<\/code>\u00a0mode compared to past versions.<\/p>\n<h2 id=\"esm-nodejs\">Experimental Nightly-Only ECMAScript Module Support in Node.js<\/h2>\n<p>For the last few years, Node.js has been working to support running ECMAScript modules (ESM). This has been a very difficult feature to support, since the foundation of the Node.js ecosystem is built on a different module system called CommonJS (CJS). Interoperating between the two brings large challenges, with many new features to juggle.<\/p>\n<p>TypeScript 4.5 initially added new settings to support directly running ECMAScript modules in Node.js; however, we believe that the current experience needs more &#8220;bake time&#8221; before it can be used more broadly. You can see more details of why\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/46452\">here<\/a>.<\/p>\n<p>In turn, this feature is still available for use, but\u00a0<strong>only under\u00a0<a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\" rel=\"nofollow\">nightly releases<\/a>\u00a0of TypeScript<\/strong>, and not in TypeScript 4.5.<\/p>\n<p>We are looking to hear what you think so far, so if you&#8217;re interested in using TypeScript and running ECMAScript modules under Node.js,\u00a0<a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/esm-node.html\" rel=\"nofollow\">read more about this feature in our documentation<\/a>,\u00a0<a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\" rel=\"nofollow\">try it out<\/a>, and give us your feedback!<\/p>\n<h2><a name=\"lib-node-modules\"><\/a>Supporting\u00a0<code>lib<\/code>\u00a0from\u00a0<code>node_modules<\/code><\/h2>\n<p>To ensure that TypeScript and JavaScript support works well out of the box, TypeScript bundles a series of declaration files (<code>.d.ts<\/code>\u00a0files). These declaration files represent the available APIs in the JavaScript language, and the standard browser DOM APIs. While there are some reasonable defaults based on your\u00a0<a href=\"https:\/\/www.typescriptlang.org\/tsconfig#target\" rel=\"nofollow\"><code>target<\/code><\/a>, you can pick and choose which declaration files your program uses by configuring the\u00a0<a href=\"https:\/\/www.typescriptlang.org\/tsconfig#lib\" rel=\"nofollow\"><code>lib<\/code><\/a>\u00a0setting in the\u00a0<code>tsconfig.json<\/code>.<\/p>\n<p>There are two occasional downsides to including these declaration files with TypeScript though:<\/p>\n<ul>\n<li>When you upgrade TypeScript, you&#8217;re also forced to handle changes to TypeScript&#8217;s built-in declaration files, and this can be a challenge when the DOM APIs change as frequently as they do.<\/li>\n<li>It is hard to customize these files to match your needs with the needs of your project&#8217;s dependencies (e.g. if your dependencies declare that they use the DOM APIs, you might also be forced into using the DOM APIs).<\/li>\n<\/ul>\n<p>TypeScript 4.5 introduces a way to override a specific built-in\u00a0<code>lib<\/code>\u00a0in a manner similar to how\u00a0<code>@types\/<\/code>\u00a0support works. When deciding which\u00a0<code>lib<\/code>\u00a0files TypeScript should include, it will first look for a scoped\u00a0<code>@typescript\/lib-*<\/code>\u00a0package in\u00a0<code>node_modules<\/code>. For example, when including\u00a0<code>dom<\/code>\u00a0as an option in\u00a0<code>lib<\/code>, TypeScript will use the types in\u00a0<code>node_modules\/@typescript\/lib-dom<\/code>\u00a0if available.<\/p>\n<p>You can then use your package manager to install a specific package to take over for a given\u00a0<code>lib<\/code>\u00a0For example, today TypeScript publishes versions of the DOM APIs on\u00a0<code>@types\/web<\/code>. If you wanted to lock your project to a specific version of the DOM APIs, you could add this to your\u00a0<code>package.json<\/code>:<\/p>\n<div class=\"highlight highlight-source-json position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\">{\r\n <span style=\"color: #a31515;\">\"dependencies\"<\/span>: {\r\n    <span style=\"color: #a31515;\">\"@typescript\/lib-dom\"<\/span>: <span style=\"color: #a31515;\"><span class=\"pl-pds\">\"<\/span>npm:@types\/web<span class=\"pl-pds\">\"<\/span><\/span>\r\n  }\r\n}<\/pre>\n<\/div>\n<p>Then from 4.5 onwards, you can update TypeScript and your dependency manager&#8217;s lockfile will ensure that it uses the exact same version of the DOM types. That means you get to update your types on your own terms.<\/p>\n<p>We&#8217;d like to give a shout-out to\u00a0<a href=\"https:\/\/github.com\/saschanaz\">saschanaz<\/a>\u00a0who has been extremely helpful and patient as we&#8217;ve been building out and experimenting with this feature.<\/p>\n<p>For more information, you can\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45771\">see the implementation of this change<\/a>.<\/p>\n<h2 id=\"awaited-type\">The\u00a0<code>Awaited<\/code>\u00a0Type and\u00a0<code>Promise<\/code>\u00a0Improvements<\/h2>\n<p>TypeScript 4.5 introduces a new utility type called the\u00a0<code>Awaited<\/code>\u00a0type. This type is meant to model operations like\u00a0<code>await<\/code>\u00a0in\u00a0<code>async<\/code>\u00a0functions, or the\u00a0<code>.then()<\/code>\u00a0method on\u00a0<code>Promise<\/code>s &#8211; specifically, the way that they recursively unwrap\u00a0<code>Promise<\/code>s.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ A = string<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">A<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">Awaited<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ B = number<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">B<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">Awaited<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ C = boolean | number<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">Awaited<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">boolean<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>The\u00a0<code>Awaited<\/code>\u00a0type can be helpful for modeling existing APIs, including JavaScript built-ins like\u00a0<code>Promise.all<\/code>,\u00a0<code>Promise.race<\/code>, etc. In fact, some of the problems around inference with\u00a0<code>Promise.all<\/code>\u00a0served as motivations for\u00a0<code>Awaited<\/code>. Here&#8217;s an example that fails in TypeScript 4.4 and earlier.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">declare<\/span> <span style=\"color: #0000ff;\">function<\/span> <span style=\"color: #267F99;\">MaybePromise<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">value<\/span>: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #267F99;\">T<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">&gt;<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #267F99;\">PromiseLike<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">async<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">doSomething<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">result<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">await<\/span> <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">all<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">[<\/span>\r\n        <span style=\"color: #267F99;\">MaybePromise<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #09885A;\">100<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">,<\/span>\r\n        <span style=\"color: #267F99;\">MaybePromise<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #09885A;\">200<\/span><span class=\"pl-kos\">)<\/span>\r\n    <span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ Error!<\/span>\r\n    <span style=\"color: #148A14;\">\/\/<\/span>\r\n    <span style=\"color: #148A14;\">\/\/    [number | Promise&lt;100&gt;, number | Promise&lt;200&gt;]<\/span>\r\n    <span style=\"color: #148A14;\">\/\/<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ is not assignable to type<\/span>\r\n    <span style=\"color: #148A14;\">\/\/<\/span>\r\n    <span style=\"color: #148A14;\">\/\/    [number, number]<\/span>\r\n    <span style=\"color: #0000ff;\">return<\/span> <span class=\"pl-s1\">result<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>Now\u00a0<code>Promise.all<\/code>\u00a0leverages combines certain features with\u00a0<code>Awaited<\/code>\u00a0to give much better inference results, and the above example works.<\/p>\n<p>For more information, you\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45350\">can read about this change on GitHub<\/a>.<\/p>\n<h2 id=\"template-string-discriminants\">Template String Types as Discriminants<\/h2>\n<p>TypeScript 4.5 now can narrow values that have template string types, and also recognizes template string types as discriminants.<\/p>\n<p>As an example, the following used to fail, but now successfully type-checks in TypeScript 4.5.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Success<\/span> <span class=\"pl-kos\">{<\/span>\r\n    type: <span style=\"color: #a31515;\">`${<\/span><span style=\"color: #0000ff;\">string<\/span><span style=\"color: #a31515;\">}Success`<\/span>;\r\n    body: <span style=\"color: #0000ff;\">string<\/span>;\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Error<\/span> <span class=\"pl-kos\">{<\/span>\r\n    type: <span style=\"color: #a31515;\">`${<\/span><span style=\"color: #0000ff;\">string<\/span><span style=\"color: #a31515;\">}Error`<\/span>;\r\n    message: <span style=\"color: #0000ff;\">string<\/span>;\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">handler<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">r<\/span>: <span style=\"color: #267F99;\">Success<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #267F99;\">Error<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">r<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">type<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">\"HttpSuccess\"<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ 'r' has type 'Success'<\/span>\r\n        <span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">token<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">r<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">body<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>For more information,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/46137\">see the change that enables this feature<\/a>.<\/p>\n<h2><a name=\"module-es2022\"><\/a><code>--module es2022<\/code><\/h2>\n<p>Thanks to\u00a0<a href=\"https:\/\/github.com\/saschanaz\">Kagami S. Rosylight<\/a>, TypeScript now supports a new\u00a0<code>module<\/code>\u00a0setting:\u00a0<code>es2022<\/code>. The main feature in\u00a0<code>--module es2022<\/code>\u00a0is top-level\u00a0<code>await<\/code>, meaning you can use\u00a0<code>await<\/code>\u00a0outside of\u00a0<code>async<\/code> functions. This was already supported in\u00a0<code>--module esnext<\/code>\u00a0(and now\u00a0<code>--module nodenext<\/code>), but <code>es2022<\/code> is the first stable target for this feature.<\/p>\n<p>You can\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44656\">read up more on this change here<\/a>.<\/p>\n<h2 id=\"tailrec-conditional\">Tail-Recursion Elimination on Conditional Types<\/h2>\n<p>TypeScript often needs to gracefully fail when it detects possibly infinite recursion, or any type expansions that can take a long time and affect your editor experience. As a result, TypeScript has heuristics to make sure it doesn&#8217;t go off the rails when trying to pick apart an infinitely-deep type, or working with types that generate a lot of intermediate results.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">InfiniteBox<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">item<\/span>: <span style=\"color: #267F99;\">InfiniteBox<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">&gt;<\/span> <span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">Unpack<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">item<\/span>: infer <span style=\"color: #267F99;\">U<\/span> <span class=\"pl-kos\">}<\/span> ? <span style=\"color: #267F99;\">Unpack<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">U<\/span><span class=\"pl-kos\">&gt;<\/span> : <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ error: Type instantiation is excessively deep and possibly infinite.<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">Test<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">Unpack<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">InfiniteBox<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">&gt;<\/span><\/pre>\n<\/div>\n<p>The above example is intentionally simple and useless, but there are plenty of types that are actually useful, and unfortunately trigger our heuristics. As an example, the following\u00a0<code>TrimLeft<\/code>\u00a0type removes spaces from the beginning of a string-like type. If given a string type that has a space at the beginning, it immediately feeds the remainder of the string back into\u00a0<code>TrimLeft<\/code>.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">TrimLeft<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span>\r\n    <span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> ` ${infer <span style=\"color: #267F99;\">Rest<\/span><span class=\"pl-kos\">}<\/span>` ? <span style=\"color: #267F99;\">TrimLeft<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Rest<\/span><span class=\"pl-kos\">&gt;<\/span> : <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Test = \"hello\" | \"world\"<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">Test<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">TrimLeft<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #a31515;\">\"   hello\"<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #a31515;\">\" world\"<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>This type can be useful, but if a string has 50 leading spaces, you&#8217;ll get an error.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">TrimLeft<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span>\r\n    <span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> ` ${infer <span style=\"color: #267F99;\">Rest<\/span><span class=\"pl-kos\">}<\/span>` ? <span style=\"color: #267F99;\">TrimLeft<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Rest<\/span><span class=\"pl-kos\">&gt;<\/span> : <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ error: Type instantiation is excessively deep and possibly infinite.<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">Test<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">TrimLeft<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #a31515;\">\"                                                oops\"<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>That&#8217;s unfortunate, because these kinds of types tend to be extremely useful in modeling operations on strings &#8211; for example, parsers for URL routers. To make matters worse, a more useful type typically creates more type instantiations, and in turn has even more limitations on input length.<\/p>\n<p>But there&#8217;s a saving grace:\u00a0<code>TrimLeft<\/code>\u00a0is written in a way that is\u00a0<em>tail-recursive<\/em>\u00a0in one branch. When it calls itself again, it immediately returns the result and doesn&#8217;t do anything with it. Because these types don&#8217;t need to create any intermediate results, they can be implemented more quickly and in a way that avoids triggering many of type recursion heuristics that are built into TypeScript.<\/p>\n<p>That&#8217;s why TypeScript 4.5 performs some tail-recursion elimination on conditional types. As long as one branch of a conditional type is simply another conditional type, TypeScript can avoid intermediate instantiations. There are still heuristics to ensure that these types don&#8217;t go off the rails, but they are much more generous.<\/p>\n<p>Keep in mind, the following type\u00a0<em>won&#8217;t<\/em>\u00a0be optimized, since it uses the result of a conditional type by adding it to a union.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">GetChars<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">S<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span>\r\n    <span style=\"color: #267F99;\">S<\/span> <span style=\"color: #0000ff;\">extends<\/span> `${infer <span style=\"color: #267F99;\">Char<\/span><span class=\"pl-kos\">}<\/span>${infer <span style=\"color: #267F99;\">Rest<\/span><span class=\"pl-kos\">}<\/span>` ? <span style=\"color: #267F99;\">Char<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #267F99;\">GetChars<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Rest<\/span><span class=\"pl-kos\">&gt;<\/span> : <span style=\"color: #0000ff;\">never<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>If you would like to make it tail-recursive, you can introduce a helper that takes an &#8220;accumulator&#8221; type parameter, just like with tail-recursive functions.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">GetChars<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">S<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">GetCharsHelper<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">S<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #0000ff;\">never<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">GetCharsHelper<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">S<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">Acc<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span>\r\n    <span style=\"color: #267F99;\">S<\/span> <span style=\"color: #0000ff;\">extends<\/span> `${infer <span style=\"color: #267F99;\">Char<\/span><span class=\"pl-kos\">}<\/span>${infer <span style=\"color: #267F99;\">Rest<\/span><span class=\"pl-kos\">}<\/span>` ? <span style=\"color: #267F99;\">GetCharsHelper<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Rest<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">Char<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #267F99;\">Acc<\/span><span class=\"pl-kos\">&gt;<\/span> : <span style=\"color: #267F99;\">Acc<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>You can read up more on the implementation\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45711\">here<\/a>.<\/p>\n<h2 id=\"preserve-value-imports\">Disabling Import Elision<\/h2>\n<p>There are some cases where TypeScript can&#8217;t detect that you&#8217;re using an import. For example, take the following code:<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">Animal<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/animal.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-en\">eval<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"console.log(new Animal().isDangerous())\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>By default, TypeScript always removes this import because it appears to be unused. In TypeScript 4.5, you can enable a new flag called\u00a0<code>--preserveValueImports<\/code>\u00a0to prevent TypeScript from stripping out any imported values from your JavaScript outputs. Good reasons to use\u00a0<code>eval<\/code>\u00a0are few and far between, but something very similar to this happens in Svelte:<\/p>\n<div class=\"highlight highlight-text-html-basic position-relative overflow-auto\">\n<pre><span style=\"color: #148A14;\">&lt;!-- A .svelte File --&gt;<\/span>\r\n<span class=\"pl-kos\">&lt;<\/span><span class=\"pl-ent\">script<\/span><span class=\"pl-kos\">&gt;<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">someFunc<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">&lt;\/<\/span><span class=\"pl-ent\">script<\/span><span class=\"pl-kos\">&gt;<\/span>\r\n\r\n<span class=\"pl-kos\">&lt;<\/span><span class=\"pl-ent\">button<\/span> <span class=\"pl-c1\">on:click<\/span>=<span style=\"color: #a31515;\">{someFunc}<\/span><span class=\"pl-kos\">&gt;<\/span>Click me!<span class=\"pl-kos\">&lt;\/<\/span><span class=\"pl-ent\">button<\/span><span class=\"pl-kos\">&gt;<\/span><\/pre>\n<\/div>\n<p>along with in Vue.js, using its\u00a0<code>&lt;script setup&gt;<\/code>\u00a0feature:<\/p>\n<div class=\"highlight highlight-text-html-basic position-relative overflow-auto\">\n<pre><span style=\"color: #148A14;\">&lt;!-- A .vue File --&gt;<\/span>\r\n<span class=\"pl-kos\">&lt;<\/span><span class=\"pl-ent\">script<\/span> <span class=\"pl-c1\">setup<\/span><span class=\"pl-kos\">&gt;<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">someFunc<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">&lt;\/<\/span><span class=\"pl-ent\">script<\/span><span class=\"pl-kos\">&gt;<\/span>\r\n\r\n<span class=\"pl-kos\">&lt;<\/span><span class=\"pl-ent\">button<\/span> <span class=\"pl-c1\">@click<\/span>=\"<span style=\"color: #a31515;\">someFunc<\/span>\"<span class=\"pl-kos\">&gt;<\/span>Click me!<span class=\"pl-kos\">&lt;\/<\/span><span class=\"pl-ent\">button<\/span><span class=\"pl-kos\">&gt;<\/span><\/pre>\n<\/div>\n<p>These frameworks generate some code based on markup outside of their\u00a0<code>&lt;script&gt;<\/code>\u00a0tags, but TypeScript\u00a0<em>only<\/em>\u00a0sees code within the\u00a0<code>&lt;script&gt;<\/code>\u00a0tags. That means TypeScript will automatically drop the import of\u00a0<code>someFunc<\/code>, and the above code won&#8217;t be runnable! With TypeScript 4.5, you can use\u00a0<code>--preserveValueImports<\/code>\u00a0to avoid these situations.<\/p>\n<p>Note that this flag has a special requirement when combined with\u00a0<code>--isolatedModules<\/code>: imported types\u00a0<em>must<\/em>\u00a0be marked as type-only because compilers that process single files at a time have no way of knowing whether imports are values that appear unused, or a type that must be removed in order to avoid a runtime crash.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ Which of these is a value that should be preserved? tsc knows, but `ts.transpileModule`,<\/span>\r\n<span style=\"color: #148A14;\">\/\/ ts-loader, esbuild, etc. don't, so `isolatedModules` gives an error.<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">someFunc<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">BaseType<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/                 ^^^^^^^^<\/span>\r\n<span style=\"color: #148A14;\">\/\/ Error: 'BaseType' is a type and must be imported using a type-only import<\/span>\r\n<span style=\"color: #148A14;\">\/\/ when 'preserveValueImports' and 'isolatedModules' are both enabled.<\/span><\/pre>\n<\/div>\n<p>That makes another TypeScript 4.5 feature,\u00a0<a href=\"#type-on-import-names\"><code>type<\/code>\u00a0modifiers on import names<\/a>, especially important.<\/p>\n<p>For more information,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44619\">see the pull request here<\/a>.<\/p>\n<h2 id=\"type-on-import-names\"><code>type<\/code>\u00a0Modifiers on Import Names<\/h2>\n<p>As mentioned above,\u00a0<code>--preserveValueImports<\/code>\u00a0and\u00a0<code>--isolatedModules<\/code>\u00a0have special requirements so that there&#8217;s no ambiguity for build tools whether it&#8217;s safe to drop type imports.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ Which of these is a value that should be preserved? tsc knows, but `ts.transpileModule`,<\/span>\r\n<span style=\"color: #148A14;\">\/\/ ts-loader, esbuild, etc. don't, so `isolatedModules` issues an error.<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">someFunc<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">BaseType<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/                 ^^^^^^^^<\/span>\r\n<span style=\"color: #148A14;\">\/\/ Error: 'BaseType' is a type and must be imported using a type-only import<\/span>\r\n<span style=\"color: #148A14;\">\/\/ when 'preserveValueImports' and 'isolatedModules' are both enabled.<\/span><\/pre>\n<\/div>\n<p>When these options are combined, we need a way to signal when an import can be legitimately dropped. TypeScript already has something for this with\u00a0<code>import type<\/code>:<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span style=\"color: #0000ff;\">type<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">BaseType<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">someFunc<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Thing<\/span> <span style=\"color: #0000ff;\">implements<\/span> <span style=\"color: #267F99;\">BaseType<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>This works, but it would be nice to avoid two import statements for the same module. That&#8217;s part of why TypeScript 4.5 allows a\u00a0<code>type<\/code>\u00a0modifier on individual named imports, so that you can mix and match as needed.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">someFunc<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">BaseType<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Thing<\/span> <span style=\"color: #0000ff;\">implements<\/span> <span style=\"color: #267F99;\">BaseType<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">someMethod<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-en\">someFunc<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>In the above example,\u00a0<code>BaseType<\/code>\u00a0is always guaranteed to be erased and\u00a0<code>someFunc<\/code>\u00a0will be preserved under\u00a0<code>--preserveValueImports<\/code>, leaving us with the following code:<\/p>\n<div class=\"highlight highlight-source-js position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">someFunc<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">class<\/span> <span class=\"pl-v\">Thing<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">someMethod<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-en\">someFunc<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>For more information, see\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45998\">the changes on GitHub<\/a>.<\/p>\n<h2 id=\"private-field-presence-checks\">Private Field Presence Checks<\/h2>\n<p>TypeScript 4.5 supports an ECMAScript proposal for checking whether an object has a private field on it. You can now write a class with a\u00a0<code>#private<\/code>\u00a0field member and see whether another object has the same field by using the\u00a0<code>in<\/code>\u00a0operator.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Person<\/span> <span class=\"pl-kos\">{<\/span>\r\n    #<span class=\"pl-c1\">name<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-en\">constructor<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">name<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">name<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">name<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n\r\n    <span class=\"pl-en\">equals<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">other<\/span>: <span style=\"color: #0000ff;\">unknown<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span class=\"pl-s1\">other<\/span> <span class=\"pl-c1\">&amp;&amp;<\/span>\r\n            <span style=\"color: #0000ff;\">typeof<\/span> <span class=\"pl-s1\">other<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">\"object\"<\/span> <span class=\"pl-c1\">&amp;&amp;<\/span>\r\n            #<span class=\"pl-s1\">name<\/span> <span style=\"color: #0000ff;\">in<\/span> <span class=\"pl-s1\">other<\/span> <span class=\"pl-c1\">&amp;&amp;<\/span> <span style=\"color: #148A14;\">\/\/ &lt;- this is new!<\/span>\r\n            <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">name<\/span> <span class=\"pl-c1\">===<\/span> <span class=\"pl-s1\">other<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">name<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>One interesting aspect of this feature is that the check\u00a0<code>#name in other<\/code>\u00a0implies that\u00a0<code>other<\/code>\u00a0must have been constructed as a\u00a0<code>Person<\/code>, since there&#8217;s no other way that field could be present. This is actually one of the key features of the proposal, and it&#8217;s why the proposal is named &#8220;ergonomic brand checks&#8221; &#8211; because private fields often act as a &#8220;brand&#8221; to guard against objects that aren&#8217;t instances of their class. As such, TypeScript is able to appropriately narrow the type of\u00a0<code>other<\/code>\u00a0on each check, until it ends up with the type\u00a0<code>Person<\/code>.<\/p>\n<p>We&#8217;d like to extend a big thanks to our friends at Bloomberg\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44648\">who contributed this pull request<\/a>:\u00a0<a href=\"https:\/\/github.com\/acutmore\">Ashley Claymore<\/a>,\u00a0<a href=\"https:\/\/github.com\/dragomirtitian\">Titian Cernicova-Dragomir<\/a>,\u00a0<a href=\"https:\/\/github.com\/mkubilayk\">Kubilay Kahveci<\/a>, and\u00a0<a href=\"https:\/\/github.com\/robpalme\">Rob Palmer<\/a>!<\/p>\n<h2 id=\"import-assertions\">Import Assertions<\/h2>\n<p>TypeScript 4.5 supports an ECMAScript proposal for\u00a0<em>import assertions<\/em>. This is a syntax used by runtimes to make sure that an import has an expected format.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-s1\">obj<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/something.json\"<\/span> <span class=\"pl-s1\">assert<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #0000ff;\">type<\/span>: \"<span class=\"pl-s1\">json<\/span>\" <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>The contents of these assertions are not checked by TypeScript since they&#8217;re host-specific, and are simply left alone so that browsers and runtimes can handle them (and possibly error).<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ TypeScript is fine with this.<\/span>\r\n<span style=\"color: #148A14;\">\/\/ But your browser? Probably not.<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-s1\">obj<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/something.json\"<\/span> <span class=\"pl-s1\">assert<\/span> <span class=\"pl-kos\">{<\/span>\r\n    type: <span style=\"color: #a31515;\">\"fluffy bunny\"<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>Dynamic\u00a0<code>import()<\/code>\u00a0calls can also use import assertions through a second argument.<\/p>\n<div class=\"highlight highlight-source-ts position-relative overflow-auto\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">obj<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">await<\/span> <span style=\"color: #0000ff;\">import<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\".\/something.json\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">assert<\/span>: <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">type<\/span>: <span style=\"color: #a31515;\">\"json\"<\/span> <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><\/pre>\n<\/div>\n<p>The expected type of that second argument is defined by a new type called\u00a0<code>ImportCallOptions<\/code>, and currently only accepts an\u00a0<code>assert<\/code>\u00a0property.<\/p>\n<p>We&#8217;d like to thank\u00a0<a href=\"https:\/\/github.com\/Kingwl\/\">Wenlu Wang<\/a>\u00a0for\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/40698\">implementing this feature<\/a>!<\/p>\n<h2 id=\"real-path-sync-native\">Faster Load Time with\u00a0<code>realpathSync.native<\/code><\/h2>\n<p>TypeScript now leverages the\u00a0<code>realpathSync.native<\/code>\u00a0function in Node.js on all operating systems.<\/p>\n<p>Previously this function was only used on Linux, but in TypeScript 4.5, as long as you&#8217;re running a recent-enough version of Node.js, the compiler will also use the function on operating systems that are typically case-insensitive, like Windows and MacOS. This change sped up project loading by 5-13% on certain codebases on Windows.<\/p>\n<p>For more information, see\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44966\">the original change here<\/a>, along with\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44966\">the 4.5-specific changes here<\/a>.<\/p>\n<h2 id=\"snippet-completions\">New Snippet Completions<\/h2>\n<p>TypeScript 4.5 brings two new\u00a0<em>snippet completions<\/em>\u00a0&#8211; these are completions that add some default text and allow you to possibly tab through bits and pieces of the code that you may want to adjust.<\/p>\n<h3 id=\"subclass-method-snippets\">Snippet Completions for Methods in Classes<\/h3>\n<p>TypeScript 4.5 now provides snippet completions when overriding or implementing methods in classes.<\/p>\n<p>When implementing a method of an interface, or overriding a method in a subclass, TypeScript completes not just the method name, but also the full signature and braces of the method body. When you finish your completion, your cursor will jump into the body of the method.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/class-method-snippet-1-4-5.gif\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"When implementing a method of an interface in a class, TypeScript completes not just the method name, but also the full signature of the type.\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/class-method-snippet-1-4-5.gif\" \/><\/a><\/p>\n<p>You can\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/45670\">read up more on the development of this feature here<\/a>.<\/p>\n<h3 id=\"jsx-attribute-snippets\">Snippet Completions for JSX Attributes<\/h3>\n<p>TypeScript 4.5 brings snippet completions for JSX attributes. When writing out an attribute in a JSX tag, TypeScript will already provide suggestions for those attributes; but with snippet completions, they can save you a little bit of extra typing by adding an initializer and putting your cursor in the right place.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/jsx-attributes-snippets-4-5.gif\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"Snippet completions for JSX attributes. For a string property, quotes are automatically added. For a numeric properties, braces are added.\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/jsx-attributes-snippets-4-5.gif\" \/><\/a><\/p>\n<p>TypeScript will typically use the type of an attribute to figure out what kind of initializer to insert, but you can customize this behavior in Visual Studio Code.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/jsx-snippet-settings-4-5.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"Settings in VS Code for JSX attribute completions\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/jsx-snippet-settings-4-5.png\" \/><\/a><\/p>\n<p>Keep in mind, this feature will only work in newer versions of Visual Studio Code, so you might have to use an Insiders build to get this working. For more information,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45903\">read up on the original pull request<\/a><\/p>\n<h2 id=\"display-unresolved-types\">Better Editor Support for Unresolved Types<\/h2>\n<p>In some cases, editors will leverage a lightweight &#8220;partial&#8221; semantic mode &#8211; either while the editor is waiting for the full project to load, or in contexts like\u00a0<a href=\"https:\/\/docs.github.com\/en\/codespaces\/developing-in-codespaces\/web-based-editor\">GitHub&#8217;s web-based editor<\/a>.<\/p>\n<p>In older versions of TypeScript, if the language service couldn&#8217;t find a type, it would just print\u00a0<code>any<\/code>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-4-4.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"Hovering over a signature where Buffer isn't found, TypeScript replaces it with any.\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-4-4.png\" \/><\/a><\/p>\n<p>In the above example,\u00a0<code>Buffer<\/code>\u00a0wasn&#8217;t found, so TypeScript replaced it with\u00a0<code>any<\/code>\u00a0in\u00a0<em>quick info<\/em>. In TypeScript 4.5, TypeScript will try its best to preserve what you wrote.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-4-5.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"Hovering over a signature where Buffer isn't found, it continues to use the name Buffer.\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-4-5.png\" \/><\/a><\/p>\n<p>However, if you hover over\u00a0<code>Buffer<\/code>\u00a0itself, you&#8217;ll get a hint that TypeScript couldn&#8217;t find\u00a0<code>Buffer<\/code>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-on-type-4-5.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"TypeScript displays type Buffer = \/* unresolved *\/ any;\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-on-type-4-5.png\" \/><\/a><\/p>\n<p>Altogether, this provides a smoother experience when TypeScript doesn&#8217;t have the full program available. Keep in mind, you&#8217;ll always get an error in regular scenarios to tell you when a type isn&#8217;t found.<\/p>\n<p>For more information,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45976\">see the implementation here<\/a>.<\/p>\n<h2 id=\"breaking-changes\">Breaking Changes<\/h2>\n<h3 id=\"libdts-changes\"><code>lib.d.ts<\/code>\u00a0Changes<\/h3>\n<p>TypeScript 4.5 contains changes to its built-in declaration files which may affect your compilation; however,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript-DOM-lib-generator\/issues\/1143\">these changes were fairly minimal<\/a>, and we expect most code will be unaffected.<\/p>\n<h3 id=\"inference-changes-from-awaited\">Inference Changes from\u00a0<code>Awaited<\/code><\/h3>\n<p>Because\u00a0<code>Awaited<\/code>\u00a0is now used in\u00a0<code>lib.d.ts<\/code>\u00a0and as a result of\u00a0<code>await<\/code>, you may see certain generic types change that might cause incompatibilities; however, given many intentional design decisions around\u00a0<code>Awaited<\/code>\u00a0to avoid breakage, we expect most code will be unaffected.<\/p>\n<h3 id=\"compiler-options-checking-at-the-root-of-tsconfigjson\">Compiler Options Checking at the Root of\u00a0<code>tsconfig.json<\/code><\/h3>\n<p>It&#8217;s an easy mistake to accidentally forget about the\u00a0<code>compilerOptions<\/code>\u00a0section in a\u00a0<code>tsconfig.json<\/code>. To help catch this mistake, in TypeScript 4.5, it is an error to add a top-level field which matches any of the available options in\u00a0<code>compilerOptions<\/code>\u00a0<em>without<\/em>\u00a0having also defined\u00a0<code>compilerOptions<\/code>\u00a0in that\u00a0<code>tsconfig.json<\/code>.<\/p>\n<h3 id=\"restrictions-on-assignability-to-conditional-types\">Restrictions on Assignability to Conditional Types<\/h3>\n<p>TypeScript no longer allows types to be assignable to conditional types that use\u00a0<code>infer<\/code>, or that are distributive. Doing so previously often ended up causing major performance issues. For more information,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/46429\">see the specific change on GitHub<\/a>.<\/p>\n<h2 id=\"whats-next\">What&#8217;s Next?<\/h2>\n<p>We don&#8217;t expect many major changes to this release candidate apart from major bug fixes, so we would love to hear about your experience in trying it out! That way we can make sure this release goes out in great shape.<\/p>\n<p>So try out TypeScript 4.5 RC 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&#8217;re excited to announce our Release Candidate (RC) of TypeScript 4.5! Between now and the stable release of TypeScript 4.5, we expect no further changes apart from critical bug fixes. To get started using the RC, you can get it\u00a0through NuGet, or use npm with the following command: npm install typescript@rc You can also [&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-3192","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 our Release Candidate (RC) of TypeScript 4.5! Between now and the stable release of TypeScript 4.5, we expect no further changes apart from critical bug fixes. To get started using the RC, you can get it\u00a0through NuGet, or use npm with the following command: npm install typescript@rc You can also [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3192","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=3192"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3192\/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=3192"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=3192"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=3192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}