{"id":3209,"date":"2021-11-17T11:59:59","date_gmt":"2021-11-17T19:59:59","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=3209"},"modified":"2026-02-08T17:12:55","modified_gmt":"2026-02-09T01:12:55","slug":"announcing-typescript-4-5","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-5\/","title":{"rendered":"Announcing TypeScript 4.5"},"content":{"rendered":"<p>Today we&#8217;re excited to announce the release of TypeScript 4.5!<\/p>\n<p>If you&#8217;re not yet familiar with TypeScript, it&#8217;s a language that builds on JavaScript by adding <em>statically checked types<\/em>.\nWhen you use static types, you can run the TypeScript compiler to check for bugs like typos and mismatches in the shapes of your data, and get handy suggestions.\nThese types don&#8217;t change your program, and you can remove them to leave you with clean, readable JavaScript.\nGoing beyond catching bugs in your code, TypeScript also assists you in writing code because types can power useful tooling like auto-complete, go-to-definition, and renaming in your editor!\nYou can <a href=\"https:\/\/www.typescriptlang.org\/\">read more on our website<\/a>.<\/p>\n<p>To get started using TypeScript 4.5, you can get it <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.TypeScript.MSBuild\">through NuGet<\/a>, or use npm with the following command:<\/p>\n<pre class=\"prettyprint language-sh\" style=\"padding: 10px;border-radius: 10px;\"><code>npm install typescript\r\n<\/code><\/pre>\n<p>You can also get editor support by<\/p>\n<ul>\n<li><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=TypeScriptTeam.TypeScript-45\">Downloading for Visual Studio 2019\/2017<\/a><\/li>\n<li>Trying <a href=\"https:\/\/code.visualstudio.com\/insiders\/\">Visual Studio Code Insiders<\/a> or following directions for <a href=\"https:\/\/code.visualstudio.com\/Docs\/languages\/typescript#_using-newer-typescript-versions\">Visual Studio Code<\/a> and <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 <a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-5-beta\/\">our beta<\/a> or <a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-5-rc\/\">RC<\/a> blog posts, you can <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=\"#lib-node-modules\">Supporting <code>lib<\/code> from <code>node_modules<\/code><\/a><\/li>\n<li><a href=\"#awaited-type\">The <code>Awaited<\/code> Type and <code>Promise<\/code> Improvements<\/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> Modifiers 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=\"#jsdoc-const-and-type-arg-defaults\">Const Assertions and Default Type Arguments in JSDoc<\/a><\/li>\n<li><a href=\"#real-path-sync-native\">Faster Load Time with <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=\"#esm-nodejs\">Experimental Nightly-Only ECMAScript Module Support in Node.js<\/a><\/li>\n<li><a href=\"#breaking-changes\">Breaking Changes<\/a><\/li>\n<\/ul>\n<h2 id=\"whats-new-since-the-beta-and-rc\"><a name=\"beta-delta\"><\/a> What&#8217;s New Since the Beta and RC?<\/h2>\n<p>Since our <a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-5-beta\">beta release post<\/a> and <a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-5-rc\">RC 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 <a href=\"#esm-nodejs\">ECMAScript module support for Node.js 12 has been deferred<\/a> to a future release, and is now only available as an experimental flag in nightly releases.\nThis was not an easy decision, but our team had a combination of <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/46452\">concerns around ecosystem readiness and general guidance for how\/when to use the feature<\/a>.\nWe felt it would be better to smooth out the user experience instead of releasing something that would ultimately be too frustrating for most people.\nIn the meantime though, you can still use the new support for <code>--module nodenext<\/code> and <code>--moduleResolution nodenext<\/code> as experimental features in <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\">nightly builds of TypeScript<\/a>.\nIf you try to use these settings in TypeScript 4.5, you&#8217;ll receive an error message directing you to use a nightly build instead.<\/p>\n<p>Since our RC post, we&#8217;ve added notes about <a href=\"#jsdoc-const-and-type-arg-defaults\">new JSDoc features<\/a>.\nWhile these features actually were included in the RC, they didn&#8217;t make it into our previous release notes.<\/p>\n<p>From the language editing side, we&#8217;ve introduced more snippet completions since TypeScript 4.5 beta &#8211; <a href=\"#subclass-method-snippets\">specifically, for method implementation and overrides<\/a>.<\/p>\n<p>We&#8217;ve also <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/46209\">addressed a performance regression in <code>--build<\/code> mode<\/a> due to excessive <code>realpath<\/code> calls for <code>package.json<\/code> files.\nThis change was made for TypeScript 4.5, but was also back-ported to TypeScript 4.4.4.\nIf this regression blocked you from trying TypeScript 4.4, you should see comparable or better speed in <code>--build<\/code> mode compared to past versions.<\/p>\n<h2 id=\"the-awaited-type-and-promise-improvements\"><a name=\"awaited-type\"><\/a> The <code>Awaited<\/code> Type and <code>Promise<\/code> Improvements<\/h2>\n<p>TypeScript 4.5 introduces a new utility type called the <code>Awaited<\/code> type.\nThis type is meant to model operations like <code>await<\/code> in <code>async<\/code> functions, or the <code>.then()<\/code> method on <code>Promise<\/code>s &#8211; specifically, the way that they recursively unwrap <code>Promise<\/code>s.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ A = string\r\ntype A = Awaited&lt;Promise&lt;string&gt;&gt;;\r\n\r\n\/\/ B = number\r\ntype B = Awaited&lt;Promise&lt;Promise&lt;number&gt;&gt;&gt;;\r\n\r\n\/\/ C = boolean | number\r\ntype C = Awaited&lt;boolean | Promise&lt;number&gt;&gt;;\r\n<\/code><\/pre>\n<p>The <code>Awaited<\/code> type can be helpful for modeling existing APIs, including JavaScript built-ins like <code>Promise.all<\/code>, <code>Promise.race<\/code>, etc.\nIn fact, some of the problems around inference with <code>Promise.all<\/code> served as motivations for <code>Awaited<\/code>.\nHere&#8217;s an example that fails in TypeScript 4.4 and earlier.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>declare function MaybePromise&lt;T&gt;(value: T): T | Promise&lt;T&gt; | PromiseLike&lt;T&gt;;\r\n\r\nasync function doSomething(): Promise&lt;[number, number]&gt; {\r\n    const result = await Promise.all([\r\n        MaybePromise(100),\r\n        MaybePromise(200)\r\n    ]);\r\n\r\n    \/\/ Error!\r\n    \/\/\r\n    \/\/    [number | Promise&lt;100&gt;, number | Promise&lt;200&gt;]\r\n    \/\/\r\n    \/\/ is not assignable to type\r\n    \/\/\r\n    \/\/    [number, number]\r\n    return result;\r\n}\r\n<\/code><\/pre>\n<p>Now <code>Promise.all<\/code> leverages certain features with <code>Awaited<\/code> to give much better inference results, and the above example works.<\/p>\n<p>For more information, you <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45350\">can read about this change on GitHub<\/a>.<\/p>\n<h2 id=\"supporting-lib-from-node_modules\"><a name=\"lib-node-modules\"><\/a> Supporting <code>lib<\/code> from <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> files).\nThese declaration files represent the available APIs in the JavaScript language, and the standard browser DOM APIs.\nWhile there are some reasonable defaults based on your <a href=\"https:\/\/www.typescriptlang.org\/tsconfig#target\"><code>target<\/code><\/a>, you can pick and choose which declaration files your program uses by configuring the <a href=\"https:\/\/www.typescriptlang.org\/tsconfig#lib\"><code>lib<\/code><\/a> setting in the <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 <code>lib<\/code> in a manner similar to how <code>@types\/<\/code> support works.\nWhen deciding which <code>lib<\/code> files TypeScript should include, it will first look for a scoped <code>@typescript\/lib-*<\/code> package in <code>node_modules<\/code>.\nFor example, when including <code>dom<\/code> as an option in <code>lib<\/code>, TypeScript will use the types in <code>node_modules\/@typescript\/lib-dom<\/code> if available.<\/p>\n<p>You can then use your package manager to install a specific package to take over for a given <code>lib<\/code>\nFor example, today TypeScript publishes versions of the DOM APIs on <code>@types\/web<\/code>.\nIf you wanted to lock your project to a specific version of the DOM APIs, you could add this to your <code>package.json<\/code>:<\/p>\n<pre class=\"prettyprint language-json\" style=\"padding: 10px;border-radius: 10px;\"><code>{\r\n &quot;dependencies&quot;: {\r\n    &quot;@typescript\/lib-dom&quot;: &quot;npm:@types\/web&quot;\r\n  }\r\n}\r\n<\/code><\/pre>\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.\nThat means you get to update your types on your own terms.<\/p>\n<p>We&#8217;d like to give a shout-out to  <a href=\"https:\/\/github.com\/saschanaz\">saschanaz<\/a> who 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 <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45771\">see the implementation of this change<\/a>.<\/p>\n<h2 id=\"template-string-types-as-discriminants\"><a name=\"template-string-discriminants\"><\/a> 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<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>export interface Success {\r\n    type: `${string}Success`;\r\n    body: string;\r\n}\r\n\r\nexport interface Error {\r\n    type: `${string}Error`;\r\n    message: string\r\n}\r\n\r\nexport function handler(r: Success | Error) {\r\n    if (r.type === &quot;HttpSuccess&quot;) {\r\n        \/\/ 'r' has type 'Success'\r\n        let token = r.body;\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/46137\">see the change that enables this feature<\/a>.<\/p>\n<h2 id=\"module-es2022\"><a name=\"module-es2022\"><\/a> <code>--module es2022<\/code><\/h2>\n<p>Thanks to <a href=\"https:\/\/github.com\/saschanaz\">Kagami S. Rosylight<\/a>, TypeScript now supports a new <code>module<\/code> setting: <code>es2022<\/code>.\nThe main feature in <code>--module es2022<\/code> is top-level <code>await<\/code>, meaning you can use <code>await<\/code> outside of <code>async<\/code> functions.\nThis was already supported in <code>--module esnext<\/code> (and now <code>--module nodenext<\/code>), but <code>es2022<\/code> is the first stable target for this feature.<\/p>\n<p>You can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44656\">read up more on this change here<\/a>.<\/p>\n<h2 id=\"tail-recursion-elimination-on-conditional-types\"><a name=\"tailrec-conditional\"><\/a> 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.\nAs 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<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>type InfiniteBox&lt;T&gt; = { item: InfiniteBox&lt;T&gt; }\r\n\r\ntype Unpack&lt;T&gt; = T extends { item: infer U } ? Unpack&lt;U&gt; : T;\r\n\r\n\/\/ error: Type instantiation is excessively deep and possibly infinite.\r\ntype Test = Unpack&lt;InfiniteBox&lt;number&gt;&gt;\r\n<\/code><\/pre>\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.\nAs an example, the following <code>TrimLeft<\/code> type removes spaces from the beginning of a string-like type.\nIf given a string type that has a space at the beginning, it immediately feeds the remainder of the string back into <code>TrimLeft<\/code>.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>type TrimLeft&lt;T extends string&gt; =\r\n    T extends ` ${infer Rest}` ? TrimLeft&lt;Rest&gt; : T;\r\n\r\n\/\/ Test = &quot;hello&quot; | &quot;world&quot;\r\ntype Test = TrimLeft&lt;&quot;   hello&quot; | &quot; world&quot;&gt;;\r\n<\/code><\/pre>\n<p>This type can be useful, but if a string has 50 leading spaces, you&#8217;ll get an error.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>type TrimLeft&lt;T extends string&gt; =\r\n    T extends ` ${infer Rest}` ? TrimLeft&lt;Rest&gt; : T;\r\n\r\n\/\/ error: Type instantiation is excessively deep and possibly infinite.\r\ntype Test = TrimLeft&lt;&quot;                                                oops&quot;&gt;;\r\n<\/code><\/pre>\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.\nTo 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: <code>TrimLeft<\/code> is written in a way that is <em>tail-recursive<\/em> in one branch.\nWhen it calls itself again, it immediately returns the result and doesn&#8217;t do anything with it.\nBecause 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.\nAs long as one branch of a conditional type is simply another conditional type, TypeScript can avoid intermediate instantiations.\nThere 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 <em>won&#8217;t<\/em> be optimized, since it uses the result of a conditional type by adding it to a union.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>type GetChars&lt;S&gt; =\r\n    S extends `${infer Char}${infer Rest}` ? Char | GetChars&lt;Rest&gt; : never;\r\n<\/code><\/pre>\n<p>If you would like to make it tail-recursive, you can introduce a helper that takes an &quot;accumulator&quot; type parameter, just like with tail-recursive functions.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>type GetChars&lt;S&gt; = GetCharsHelper&lt;S, never&gt;;\r\ntype GetCharsHelper&lt;S, Acc&gt; =\r\n    S extends `${infer Char}${infer Rest}` ? GetCharsHelper&lt;Rest, Char | Acc&gt; : Acc;\r\n<\/code><\/pre>\n<p>You can read up more on the implementation <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45711\">here<\/a>.<\/p>\n<h2 id=\"disabling-import-elision\"><a name=\"preserve-value-imports\"><\/a> Disabling Import Elision<\/h2>\n<p>There are some cases where TypeScript can&#8217;t detect that you&#8217;re using an import.\nFor example, take the following code:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>import { Animal } from &quot;.\/animal.js&quot;;\r\n\r\neval(&quot;console.log(new Animal().isDangerous())&quot;);\r\n<\/code><\/pre>\n<p>By default, TypeScript always removes this import because it appears to be unused.\nIn TypeScript 4.5, you can enable a new flag called <code>--preserveValueImports<\/code> to prevent TypeScript from stripping out any imported values from your JavaScript outputs.\nGood reasons to use <code>eval<\/code> are few and far between, but something very similar to this happens in Svelte:<\/p>\n<pre class=\"prettyprint language-html\" style=\"padding: 10px;border-radius: 10px;\"><code>&lt;!-- A .svelte File --&gt;\r\n&lt;script&gt;\r\nimport { someFunc } from &quot;.\/some-module.js&quot;;\r\n&lt;\/script&gt;\r\n\r\n&lt;button on:click={someFunc}&gt;Click me!&lt;\/button&gt;\r\n<\/code><\/pre>\n<p>along with in Vue.js, using its <code>&lt;script setup&gt;<\/code> feature:<\/p>\n<pre class=\"prettyprint language-html\" style=\"padding: 10px;border-radius: 10px;\"><code>&lt;!-- A .vue File --&gt;\r\n&lt;script setup&gt;\r\nimport { someFunc } from &quot;.\/some-module.js&quot;;\r\n&lt;\/script&gt;\r\n\r\n&lt;button @click=&quot;someFunc&quot;&gt;Click me!&lt;\/button&gt;\r\n<\/code><\/pre>\n<p>These frameworks generate some code based on markup outside of their <code>&lt;script&gt;<\/code> tags, but TypeScript <em>only<\/em> sees code within the <code>&lt;script&gt;<\/code> tags.\nThat means TypeScript will automatically drop the import of <code>someFunc<\/code>, and the above code won&#8217;t be runnable!\nWith TypeScript 4.5, you can use <code>--preserveValueImports<\/code> to avoid these situations.<\/p>\n<p>Note that this flag has a special requirement when combined with <code>--isolatedModules<\/code>: imported\ntypes <em>must<\/em> be 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<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ Which of these is a value that should be preserved? tsc knows, but `ts.transpileModule`,\r\n\/\/ ts-loader, esbuild, etc. don't, so `isolatedModules` gives an error.\r\nimport { someFunc, BaseType } from &quot;.\/some-module.js&quot;;\r\n\/\/                 ^^^^^^^^\r\n\/\/ Error: 'BaseType' is a type and must be imported using a type-only import\r\n\/\/ when 'preserveValueImports' and 'isolatedModules' are both enabled.\r\n<\/code><\/pre>\n<p>That makes another TypeScript 4.5 feature, <a href=\"#type-on-import-names\"><code>type<\/code> modifiers on import names<\/a>, especially important.<\/p>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44619\">see the pull request here<\/a>.<\/p>\n<h2 id=\"type-modifiers-on-import-names\"><a name=\"type-on-import-names\"><\/a> <code>type<\/code> Modifiers on Import Names<\/h2>\n<p>As mentioned above, <code>--preserveValueImports<\/code> and <code>--isolatedModules<\/code> have special requirements so that there&#8217;s no ambiguity for build tools whether it&#8217;s safe to drop type imports.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ Which of these is a value that should be preserved? tsc knows, but `ts.transpileModule`,\r\n\/\/ ts-loader, esbuild, etc. don't, so `isolatedModules` issues an error.\r\nimport { someFunc, BaseType } from &quot;.\/some-module.js&quot;;\r\n\/\/                 ^^^^^^^^\r\n\/\/ Error: 'BaseType' is a type and must be imported using a type-only import\r\n\/\/ when 'preserveValueImports' and 'isolatedModules' are both enabled.\r\n<\/code><\/pre>\n<p>When these options are combined, we need a way to signal when an import can be legitimately dropped.\nTypeScript already has something for this with <code>import type<\/code>:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>import type { BaseType } from &quot;.\/some-module.js&quot;;\r\nimport { someFunc } from &quot;.\/some-module.js&quot;;\r\n\r\nexport class Thing implements BaseType {\r\n    \/\/ ...\r\n}\r\n<\/code><\/pre>\n<p>This works, but it would be nice to avoid two import statements for the same module.\nThat&#8217;s part of why TypeScript 4.5 allows a <code>type<\/code> modifier on individual named imports, so that you can mix and match as needed.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>import { someFunc, type BaseType } from &quot;.\/some-module.js&quot;;\r\n\r\nexport class Thing implements BaseType {\r\n    someMethod() {\r\n        someFunc();\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>In the above example, <code>BaseType<\/code> is always guaranteed to be erased and <code>someFunc<\/code> will be preserved under <code>--preserveValueImports<\/code>, leaving us with the following code:<\/p>\n<pre class=\"prettyprint language-javascript\" style=\"padding: 10px;border-radius: 10px;\"><code>import { someFunc } from &quot;.\/some-module.js&quot;;\r\n\r\nexport class Thing {\r\n    someMethod() {\r\n        someFunc();\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>For more information, see <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45998\">the changes on GitHub<\/a>.<\/p>\n<h2 id=\"private-field-presence-checks\"><a name=\"private-field-presence-checks\"><\/a> 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.\nYou can now write a class with a <code>#private<\/code> field member and see whether another object has the same field by using the <code>in<\/code> operator.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>class Person {\r\n    #name: string;\r\n    constructor(name: string) {\r\n        this.#name = name;\r\n    }\r\n\r\n    equals(other: unknown) {\r\n        return other &amp;&amp;\r\n            typeof other === &quot;object&quot; &amp;&amp;\r\n            #name in other &amp;&amp; \/\/ &lt;- this is new!\r\n            this.#name === other.#name;\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>One interesting aspect of this feature is that the check <code>#name in other<\/code> implies that <code>other<\/code> must have been constructed as a <code>Person<\/code>, since there&#8217;s no other way that field could be present.\nThis is actually one of the key features of the proposal, and it&#8217;s why the proposal is named &quot;ergonomic brand checks&quot; &#8211; because private fields often act as a &quot;brand&quot; to guard against objects that aren&#8217;t instances of their class.\nAs such, TypeScript is able to appropriately narrow the type of <code>other<\/code> on each check, until it ends up with the type <code>Person<\/code>.<\/p>\n<p>We&#8217;d like to extend a big thanks to our friends at Bloomberg <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44648\">who contributed this pull request<\/a>: <a href=\"https:\/\/github.com\/acutmore\">Ashley Claymore<\/a>, <a href=\"https:\/\/github.com\/dragomirtitian\">Titian Cernicova-Dragomir<\/a>, <a href=\"https:\/\/github.com\/mkubilayk\">Kubilay Kahveci<\/a>, and <a href=\"https:\/\/github.com\/robpalme\">Rob Palmer<\/a>!<\/p>\n<h2 id=\"import-assertions\"><a name=\"import-assertions\"><\/a> Import Assertions<\/h2>\n<p>TypeScript 4.5 supports an ECMAScript proposal for <em>import assertions<\/em>.\nThis is a syntax used by runtimes to make sure that an import has an expected format.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>import obj from &quot;.\/something.json&quot; assert { type: &quot;json&quot; };\r\n<\/code><\/pre>\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<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ TypeScript is fine with this.\r\n\/\/ But your browser? Probably not.\r\nimport obj from &quot;.\/something.json&quot; assert {\r\n    type: &quot;fluffy bunny&quot;\r\n};\r\n<\/code><\/pre>\n<p>Dynamic <code>import()<\/code> calls can also use import assertions through a second argument.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>const obj = await import(&quot;.\/something.json&quot;, {\r\n    assert: { type: &quot;json&quot; }\r\n})\r\n<\/code><\/pre>\n<p>The expected type of that second argument is defined by a new type called <code>ImportCallOptions<\/code>, and currently only accepts an <code>assert<\/code> property.<\/p>\n<p>We&#8217;d like to thank <a href=\"https:\/\/github.com\/Kingwl\/\">Wenlu Wang<\/a> for <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/40698\">implementing this feature<\/a>!<\/p>\n<h2 id=\"const-assertions-and-default-type-arguments-in-jsdoc\"><a name=\"jsdoc-const-and-type-arg-defaults\"><\/a> Const Assertions and Default Type Arguments in JSDoc<\/h2>\n<p>TypeScript 4.5 brings some extra expressivity to our JSDoc support.<\/p>\n<p>One example of this is with <code>const<\/code> assertions.\nIn TypeScript, you can get a more precise and immutable type by writing <code>as const<\/code> after a literal.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ type is { prop: string }\r\nlet a = { prop: &quot;hello&quot; };\r\n\r\n\/\/ type is { readonly prop: &quot;hello&quot; }\r\nlet b = { prop: &quot;hello&quot; } as const;\r\n<\/code><\/pre>\n<p>In JavaScript files, you can now use JSDoc type assertions to achieve the same thing.<\/p>\n<pre class=\"prettyprint language-javascript\" style=\"padding: 10px;border-radius: 10px;\"><code>\/\/ type is { prop: string }\r\nlet a = { prop: &quot;hello&quot; };\r\n\r\n\/\/ type is { readonly prop: &quot;hello&quot; }\r\nlet b = \/** @type {const} *\/ ({ prop: &quot;hello&quot; });\r\n<\/code><\/pre>\n<p>As a reminder, JSDoc type assertions comments start with <code>\/** @type {TheTypeWeWant} *\/<\/code> and are followed by a parenthesized expression:<\/p>\n<pre class=\"prettyprint language-javascript\" style=\"padding: 10px;border-radius: 10px;\"><code>\/** @type {TheTypeWeWant} *\/` (someExpression)\r\n<\/code><\/pre>\n<p>TypeScript 4.5 also adds default type arguments to JSDoc, which means the following <code>type<\/code> declaration in TypeScript:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>type Foo&lt;T extends string | number = number&gt; = { prop: T };\r\n<\/code><\/pre>\n<p>can be rewritten as the following <code>@typedef<\/code> declaration in JavaScript:<\/p>\n<pre class=\"prettyprint language-javascript\" style=\"padding: 10px;border-radius: 10px;\"><code>\/**\r\n * @template {string | number} [T=number]\r\n * @typedef Foo\r\n * @property prop {T}\r\n *\/\r\n\r\n\/\/ or\r\n\r\n\/**\r\n * @template {string | number} [T=number]\r\n * @typedef {{ prop: T }} Foo\r\n *\/\r\n<\/code><\/pre>\n<p>For more information, see <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45464\">the pull request for <code>const<\/code> assertions<\/a> along with <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45483\">the changes for type argument defaults<\/a>.<\/p>\n<h2 id=\"faster-load-time-with-realpathsyncnative\"><a name=\"real-path-sync-native\"><\/a> Faster Load Time with <code>realpathSync.native<\/code><\/h2>\n<p>TypeScript now leverages the <code>realpathSync.native<\/code> function 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.\nThis change sped up project loading by 5-13% on certain codebases on Windows.<\/p>\n<p>For more information, see <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44966\">the original change here<\/a>, along with <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44966\">the 4.5-specific changes here<\/a>.<\/p>\n<h2 id=\"new-snippet-completions\"><a name=\"snippet-completions\"><\/a> New Snippet Completions<\/h2>\n<p>TypeScript 4.5 brings two new <em>snippet completions<\/em> &#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=\"snippet-completions-for-methods-in-classes\"><a name=\"subclass-method-snippets\"><\/a> 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.\nWhen you finish your completion, your cursor will jump into the body of the method.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/class-method-snippet-1-4-5.gif\" 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.\"><\/p>\n<p>You can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/45670\">read up more on the development of this feature here<\/a>.<\/p>\n<h3 id=\"snippet-completions-for-jsx-attributes\"><a name=\"jsx-attribute-snippets\"><\/a> Snippet Completions for JSX Attributes<\/h3>\n<p>TypeScript 4.5 brings snippet completions for JSX attributes.\nWhen writing out an attribute in a JSX tag, TypeScript will already provide suggestions for those attributes;\nbut 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><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/jsx-attributes-snippets-4-5.gif\" alt=\"Snippet completions for JSX attributes. For a string property, quotes are automatically added. For a numeric properties, braces are added.\"><\/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><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/jsx-snippet-settings-4-5.png\" alt=\"Settings in VS Code for JSX attribute completions\"><\/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.\nFor more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45903\">read up on the original pull request<\/a><\/p>\n<h2 id=\"better-editor-support-for-unresolved-types\"><a name=\"display-unresolved-types\"><\/a> Better Editor Support for Unresolved Types<\/h2>\n<p>In some cases, editors will leverage a lightweight &quot;partial&quot; semantic mode &#8211; either while the editor is waiting for the full project to load, or in contexts like <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 <code>any<\/code>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-4-4.png\" alt=\"Hovering over a signature where  isn't found, TypeScript replaces it with .\"><\/p>\n<p>In the above example, <code>Buffer<\/code> wasn&#8217;t found, so TypeScript replaced it with <code>any<\/code> in <em>quick info<\/em>.\nIn TypeScript 4.5, TypeScript will try its best to preserve what you wrote.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-4-5.png\" alt=\"Hovering over a signature where  isn't found, it continues to use the name .\"><\/p>\n<p>However, if you hover over <code>Buffer<\/code> itself, you&#8217;ll get a hint that TypeScript couldn&#8217;t find <code>Buffer<\/code>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/10\/quick-info-unresolved-on-type-4-5.png\" alt=\"TypeScript displays \"><\/p>\n<p>Altogether, this provides a smoother experience when TypeScript doesn&#8217;t have the full program available.\nKeep 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, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/45976\">see the implementation here<\/a>.<\/p>\n<h2 id=\"experimental-nightly-only-ecmascript-module-support-in-nodejs\"><a name=\"esm-nodejs\"><\/a> 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).\nThis 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).\nInteroperating 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;\nhowever, we believe that the current experience needs more &quot;bake time&quot; before it can be used more broadly.\nYou can see more details of why <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/46452\">here<\/a>.<\/p>\n<p>In turn, this feature is still available for use, but <strong>only under <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\">nightly releases<\/a> of 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, <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/esm-node.html\">read more about this feature in our documentation<\/a>, <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\">try it out<\/a>, and give us your feedback!<\/p>\n<h2 id=\"breaking-changes\"><a name=\"breaking-changes\"><\/a> Breaking Changes<\/h2>\n<h3 id=\"libdts-changes\"><code>lib.d.ts<\/code> Changes<\/h3>\n<p>TypeScript 4.5 contains changes to its built-in declaration files which may affect your compilation;\nhowever, <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 <code>Awaited<\/code><\/h3>\n<p>Because <code>Awaited<\/code> is now used in <code>lib.d.ts<\/code> and as a result of <code>await<\/code>, you may see certain generic types change that might cause incompatibilities.\nThis may cause issues when providing explicit type arguments to functions like <code>Promise.all<\/code>, <code>Promise.allSettled<\/code>, etc.<\/p>\n<p>Often, you can make a fix by removing type arguments altogether.<\/p>\n<pre class=\"prettyprint language-diff\" style=\"padding: 10px;border-radius: 10px;\"><code>- Promise.all&lt;boolean, boolean&gt;(...)\r\n+ Promise.all(...)\r\n<\/code><\/pre>\n<p>More involved cases will require you to replace a list of type arguments with a single type argument of a tuple-like type.<\/p>\n<pre class=\"prettyprint language-diff\" style=\"padding: 10px;border-radius: 10px;\"><code>- Promise.all&lt;boolean, boolean&gt;(...)\r\n+ Promise.all&lt;[boolean, boolean]&gt;(...)\r\n<\/code><\/pre>\n<p>However, there will be occasions when a fix will be a little bit more involved, and replacing the types with a tuple of the original type arguments won&#8217;t be enough.\n<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/46651#issuecomment-959791706\">One example where this occasionally comes up<\/a> is when an element is possibly a <code>Promise<\/code> or non-<code>Promise<\/code>.\nIn those cases, it&#8217;s no longer okay to unwrap the underlying element type.<\/p>\n<pre class=\"prettyprint language-diff\" style=\"padding: 10px;border-radius: 10px;\"><code>- Promise.all&lt;boolean | undefined, boolean | undefined&gt;(...)\r\n+ Promise.all&lt;[Promise&lt;boolean&gt; | undefined, Promise&lt;boolean&gt; | undefined]&gt;(...)\r\n<\/code><\/pre>\n<h3 id=\"template-strings-use-concat\">Template Strings Use <code>.concat()<\/code><\/h3>\n<p>Template strings in TypeScript previously just used the <code>+<\/code> operator when targeting ES3 or ES5;\nhowever, this leads to some divergences between the use of <code>.valueOf()<\/code> and <code>.toString()<\/code> which ends up being less spec-compliant.\nThis is usually not noticeable, but is particularly important when using upcoming standard library additions like <a href=\"https:\/\/tc39.es\/proposal-temporal\/docs\/\">Temporal<\/a>.<\/p>\n<p>TypeScript now uses calls to <code>.concat()<\/code> on <code>strings<\/code>.\nThis gives code the same behavior regardless of whether it targets ES3 and ES5, or ES2015 and later.\nMost code should be unaffected, but you might now see different results on values that define separate <code>valueOf()<\/code> and <code>toString()<\/code> methods.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px;border-radius: 10px;\"><code>import moment = require(&quot;moment&quot;);\r\n\r\n\/\/ Before: &quot;Moment: Wed Nov 17 2021 16:23:57 GMT-0800&quot;\r\n\/\/  After: &quot;Moment: 1637195037348&quot;\r\nconsole.log(`Moment: ${moment()}`);\r\n<\/code><\/pre>\n<p>More more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/39744\">see the original issue<\/a>.<\/p>\n<h3 id=\"compiler-options-checking-at-the-root-of-tsconfigjson\">Compiler Options Checking at the Root of <code>tsconfig.json<\/code><\/h3>\n<p>It&#8217;s an easy mistake to accidentally forget about the <code>compilerOptions<\/code> section in a <code>tsconfig.json<\/code>.\nTo 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 <code>compilerOptions<\/code> <em>without<\/em> having also defined <code>compilerOptions<\/code> in that <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 <code>infer<\/code>, or that are distributive.\nDoing so previously often ended up causing major performance issues.\nFor more information, <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&#8217;re already working on TypeScript 4.6!\nIf you&#8217;re curious to hear more, you can check out the <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/milestone\/151\">4.6 milestone on GitHub<\/a> until the iteration plan is posted on the TypeScript issue tracker.\nWe currently intend to focus on performance and stability in the next release.<\/p>\n<p>In the meantime, we think TypeScript 4.5 should bring you a lot to love, with many great quality-of-life improvements!\nWe hope that this release makes coding a joy.<\/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 the release of TypeScript 4.5! If you&#8217;re not yet familiar with TypeScript, it&#8217;s a language that builds on JavaScript by adding statically checked types. When you use static types, you can run the TypeScript compiler to check for bugs like typos and mismatches in the shapes of your data, and [&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-3209","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-typescript"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re excited to announce the release of TypeScript 4.5! If you&#8217;re not yet familiar with TypeScript, it&#8217;s a language that builds on JavaScript by adding statically checked types. When you use static types, you can run the TypeScript compiler to check for bugs like typos and mismatches in the shapes of your data, and [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3209","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=3209"}],"version-history":[{"count":2,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3209\/revisions"}],"predecessor-version":[{"id":5046,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3209\/revisions\/5046"}],"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=3209"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=3209"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=3209"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}