{"id":3042,"date":"2021-08-12T14:27:02","date_gmt":"2021-08-12T22:27:02","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=3042"},"modified":"2021-08-13T10:47:34","modified_gmt":"2021-08-13T18:47:34","slug":"announcing-typescript-4-4-rc","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-4-rc\/","title":{"rendered":"Announcing TypeScript 4.4 RC"},"content":{"rendered":"<p>Today we&#8217;re excited to announce our Release Candidate (RC) of TypeScript 4.4! Between now and the stable release of TypeScript 4.4, 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\">\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-44rc\" rel=\"nofollow\">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\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>Some major highlights of TypeScript 4.4 are:<\/p>\n<ul>\n<li><a href=\"#cfa-aliased-conditions\">Control Flow Analysis of Aliased Conditions and Discriminants<\/a><\/li>\n<li><a href=\"#symbol-template-signatures\">Symbol and Template String Pattern Index Signatures<\/a><\/li>\n<li><a href=\"#use-unknown-catch-variables\">Defaulting to the\u00a0<code>unknown<\/code>\u00a0Type in Catch Variables (<code>--useUnknownInCatchVariables<\/code>)<\/a><\/li>\n<li><a href=\"#exact-optional-property-types\">Exact Optional Property Types (<code>--exactOptionalPropertyTypes<\/code>)<\/a><\/li>\n<li><a href=\"#static-blocks\">Class\u00a0<code>static<\/code>\u00a0Blocks<\/a><\/li>\n<li><a href=\"#tsc-help\"><code>tsc --help<\/code>\u00a0Updates and Improvements<\/a><\/li>\n<li><a href=\"#perf-improvements\">Performance Improvements<\/a><\/li>\n<li><a href=\"#spelling-corrections-js\">Spelling Suggestions for JavaScript<\/a><\/li>\n<li><a href=\"#inlay-hints\">Inlay Hints<\/a><\/li>\n<li><a href=\"#breaking-changes\">Breaking Changes<\/a><\/li>\n<\/ul>\n<p>Let&#8217;s explore these in more detail!<\/p>\n<h2 id=\"cfa-aliased-conditions\">Control Flow Analysis of Aliased Conditions and Discriminants<\/h2>\n<p>In JavaScript, we often have to probe a variable in different ways to see if it has a more specific type that we can use. TypeScript understands these checks and calls them\u00a0<em>type guards<\/em>. Instead of having to convince TypeScript of a variable&#8217;s type whenever we use it, the type-checker leverages something called\u00a0<em>control flow analysis<\/em>\u00a0to deduce the type within every language construct.<\/p>\n<p>For example, we can write something like<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">arg<\/span>: <span style=\"color: #0000ff;\">unknown<\/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 style=\"color: #0000ff;\">typeof<\/span> <span class=\"pl-s1\">arg<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">\"string\"<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ We know this is a string now.<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">arg<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toUpperCase<\/span><span class=\"pl-kos\">(<\/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 this example, we checked whether\u00a0<code>arg<\/code>\u00a0was a\u00a0<code>string<\/code>. TypeScript recognized the\u00a0<code>typeof arg === \"string\"<\/code>\u00a0check, which it considered a type guard, and was able to determine that\u00a0<code>arg<\/code>\u00a0should be a\u00a0<code>string<\/code>\u00a0in the body of the\u00a0<code>if<\/code>\u00a0block.<\/p>\n<p>However, what happens if we move the condition out to a constant?<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">arg<\/span>: <span style=\"color: #0000ff;\">unknown<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">argIsString<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">typeof<\/span> <span class=\"pl-s1\">arg<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">\"string\"<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">argIsString<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">arg<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toUpperCase<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span style=\"color: #148A14;\">\/\/              ~~~~~~~~~~~<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ Error! Property 'toUpperCase' does not exist on type 'unknown'.<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>In previous versions of TypeScript, this would be an error &#8211; even though\u00a0<code>argIsString<\/code>\u00a0was assigned the value of a type guard, TypeScript simply lost that information. That&#8217;s unfortunate since we might want to re-use the same check in several places. To get around that, users often have to repeat themselves or use type assertions (casts).<\/p>\n<p>In TypeScript 4.4, that is no longer the case. The above example works with no errors! When TypeScript sees that we are testing a constant value, it will do a little bit of extra work to see if it contains a type guard. If that type guard operates on a\u00a0<code>const<\/code>, a\u00a0<code>readonly<\/code>\u00a0property, or an un-modified parameter, then TypeScript is able to narrow that value appropriately.<\/p>\n<p>Different sorts of type guard conditions are preserved &#8211; not just\u00a0<code>typeof<\/code>\u00a0checks. For example, checks on discriminated unions work like a charm.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\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;\">Shape<\/span> <span class=\"pl-c1\">=<\/span>\r\n    <span class=\"pl-c1\">|<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">kind<\/span>: <span style=\"color: #a31515;\">\"circle\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-c1\">radius<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">}<\/span>\r\n    <span class=\"pl-c1\">|<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">kind<\/span>: <span style=\"color: #a31515;\">\"square\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-c1\">sideLength<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">area<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">shape<\/span>: <span style=\"color: #267F99;\">Shape<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">isCircle<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">shape<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">kind<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">\"circle\"<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">isCircle<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ We know we have a circle here!<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #267F99;\">Math<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">PI<\/span> <span class=\"pl-c1\">*<\/span> <span class=\"pl-s1\">shape<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">radius<\/span> <span class=\"pl-c1\">**<\/span> <span style=\"color: #09885A;\">2<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n    <span style=\"color: #0000ff;\">else<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ We know we're left with a square here!<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span class=\"pl-s1\">shape<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">sideLength<\/span> <span class=\"pl-c1\">**<\/span> <span style=\"color: #09885A;\">2<\/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>Analysis on discriminants in 4.4 also goes a little bit deeper &#8211; we can now extract out discriminants and TypeScript can narrow the original object.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\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;\">Shape<\/span> <span class=\"pl-c1\">=<\/span>\r\n    <span class=\"pl-c1\">|<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">kind<\/span>: <span style=\"color: #a31515;\">\"circle\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-c1\">radius<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">}<\/span>\r\n    <span class=\"pl-c1\">|<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">kind<\/span>: <span style=\"color: #a31515;\">\"square\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-c1\">sideLength<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">area<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">shape<\/span>: <span style=\"color: #267F99;\">Shape<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ Extract out the 'kind' field first.<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-kos\">{<\/span> kind <span class=\"pl-kos\">}<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">shape<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">kind<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">\"circle\"<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ We know we have a circle here!<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #267F99;\">Math<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">PI<\/span> <span class=\"pl-c1\">*<\/span> <span class=\"pl-s1\">shape<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">radius<\/span> <span class=\"pl-c1\">**<\/span> <span style=\"color: #09885A;\">2<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n    <span style=\"color: #0000ff;\">else<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ We know we're left with a square here!<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span class=\"pl-s1\">shape<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">sideLength<\/span> <span class=\"pl-c1\">**<\/span> <span style=\"color: #09885A;\">2<\/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>As another example, here&#8217;s a function that checks whether two of its inputs have contents.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">doSomeChecks<\/span><span class=\"pl-kos\">(<\/span>\r\n    <span class=\"pl-s1\">inputA<\/span>: <span style=\"color: #0000ff;\">string<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #0000ff;\">undefined<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-s1\">inputB<\/span>: <span style=\"color: #0000ff;\">string<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #0000ff;\">undefined<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-s1\">shouldDoExtraWork<\/span>: <span style=\"color: #0000ff;\">boolean<\/span><span class=\"pl-kos\">,<\/span>\r\n<span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">mustDoWork<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">inputA<\/span> <span class=\"pl-c1\">&amp;&amp;<\/span> <span class=\"pl-s1\">inputB<\/span> <span class=\"pl-c1\">&amp;&amp;<\/span> <span class=\"pl-s1\">shouldDoExtraWork<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">mustDoWork<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ Can access 'string' properties on both 'inputA' and 'inputB'!<\/span>\r\n        <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">upperA<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">inputA<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toUpperCase<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">upperB<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">inputB<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toUpperCase<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>TypeScript can understand that both\u00a0<code>inputA<\/code>\u00a0and\u00a0<code>inputB<\/code>\u00a0are both present if\u00a0<code>mustDoWork<\/code>\u00a0is\u00a0<code>true<\/code>. That means we don&#8217;t have to write a non-null assertion like\u00a0<code>inputA!<\/code>\u00a0to convince TypeScript that\u00a0<code>inputA<\/code>\u00a0isn&#8217;t\u00a0<code>undefined<\/code>.<\/p>\n<p>One neat feature here is that this analysis works transitively. If we have a constant assigned to a condition which has more constants in it, and those constants are each assigned type guards, then TypeScript can propagate the conditions later on.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">f<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">x<\/span>: <span style=\"color: #0000ff;\">string<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #0000ff;\">boolean<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">isString<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">typeof<\/span> <span class=\"pl-s1\">x<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">\"string\"<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">isNumber<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">typeof<\/span> <span class=\"pl-s1\">x<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">\"number\"<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">isStringOrNumber<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">isString<\/span> <span class=\"pl-c1\">||<\/span> <span class=\"pl-s1\">isNumber<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">isStringOrNumber<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-s1\">x<\/span><span class=\"pl-kos\">;<\/span>  <span style=\"color: #148A14;\">\/\/ Type of 'x' is 'string | number'.<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n    <span style=\"color: #0000ff;\">else<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-s1\">x<\/span><span class=\"pl-kos\">;<\/span>  <span style=\"color: #148A14;\">\/\/ Type of 'x' is 'boolean'.<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>Note that there&#8217;s a cutoff &#8211; TypeScript doesn&#8217;t go arbitrarily deep when checking these conditions, but its analysis is deep enough for most checks.<\/p>\n<p>This feature should make a lot of intuitive JavaScript code &#8220;just work&#8221; in TypeScript without it getting in your way. For more details,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44730\">check out the implementation on GitHub<\/a>!<\/p>\n<h2 id=\"symbol-template-signatures\">Symbol and Template String Pattern Index Signatures<\/h2>\n<p>TypeScript lets us describe objects where every property has to have a certain type using\u00a0<em>index signatures<\/em>. This allows us to use these objects as dictionary-like types, where we can use string keys to index into them with square brackets.<\/p>\n<p>For example, we can write a type with an index signature that accepts\u00a0<code>string<\/code>\u00a0keys and maps to\u00a0<code>boolean<\/code>\u00a0values. If we try to assign anything other than a\u00a0<code>boolean<\/code>\u00a0value, we&#8217;ll get an error.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">BooleanDictionary<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">key<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">boolean<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">declare<\/span> <span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">myDict<\/span>: <span style=\"color: #267F99;\">BooleanDictionary<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Valid to assign boolean values<\/span>\r\n<span class=\"pl-s1\">myDict<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #a31515;\">\"foo\"<\/span><span class=\"pl-kos\">]<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">true<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-s1\">myDict<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #a31515;\">\"bar\"<\/span><span class=\"pl-kos\">]<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">false<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Error, \"oops\" isn't a boolean<\/span>\r\n<span class=\"pl-s1\">myDict<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #a31515;\">\"baz\"<\/span><span class=\"pl-kos\">]<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"oops\"<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>While\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Map\" rel=\"nofollow\">a\u00a0<code>Map<\/code>\u00a0might be a better data structure here<\/a>\u00a0(specifically, a\u00a0<code>Map&lt;string, boolean&gt;<\/code>), JavaScript objects are often more convenient to use or just happen to be what we&#8217;re given to work with.<\/p>\n<p>Similarly,\u00a0<code>Array&lt;T&gt;<\/code>\u00a0already defines a\u00a0<code>number<\/code>\u00a0index signature that lets us insert\/retrieve values of type\u00a0<code>T<\/code>.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ This is part of TypeScript's definition of the built-in Array type.<\/span>\r\n<span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Array<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">index<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">arr<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">Array<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Valid<\/span>\r\n<span class=\"pl-s1\">arr<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #09885A;\">0<\/span><span class=\"pl-kos\">]<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"hello!\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Error, expecting a 'string' value here<\/span>\r\n<span class=\"pl-s1\">arr<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #09885A;\">1<\/span><span class=\"pl-kos\">]<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">123<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>Index signatures are very useful to express lots of code out in the wild; however, until now they&#8217;ve been limited to\u00a0<code>string<\/code>\u00a0and\u00a0<code>number<\/code>\u00a0keys (and\u00a0<code>string<\/code>\u00a0index signatures have an intentional quirk where they can accept\u00a0<code>number<\/code>\u00a0keys since they&#8217;ll be coerced to strings anyway). That means that TypeScript didn&#8217;t allow indexing objects with\u00a0<code>symbol<\/code>\u00a0keys. TypeScript also couldn&#8217;t model an index signature of some\u00a0<em>subset<\/em>\u00a0of\u00a0<code>string<\/code>\u00a0keys &#8211; for example, an index signature which describes just properties whose names start with the text\u00a0<code>data-<\/code>.<\/p>\n<p>TypeScript 4.4 addresses these limitations, and allows index signatures for\u00a0<code>symbol<\/code>s and template string patterns.<\/p>\n<p>For example, TypeScript now allows us to declare a type that can be keyed on arbitrary\u00a0<code>symbol<\/code>s.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Colors<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">sym<\/span>: <span style=\"color: #0000ff;\">symbol<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">red<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">Symbol<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"red\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">green<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">Symbol<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"green\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">blue<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">Symbol<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"blue\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">colors<\/span>: <span style=\"color: #267F99;\">Colors<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span><span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-s1\">colors<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">red<\/span><span class=\"pl-kos\">]<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">255<\/span><span class=\"pl-kos\">;<\/span>          <span style=\"color: #148A14;\">\/\/ Assignment of a number is allowed<\/span>\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">redVal<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">colors<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">red<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">;<\/span>   <span style=\"color: #148A14;\">\/\/ 'redVal' has the type 'number'<\/span>\r\n\r\n<span class=\"pl-s1\">colors<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">blue<\/span><span class=\"pl-kos\">]<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"da ba dee\"<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ Error: Type 'string' is not assignable to type 'number'.<\/span><\/pre>\n<\/div>\n<p>Similarly, we can write an index signature with template string pattern type. One use of this might be to exempt properties starting with\u00a0<code>data-<\/code>\u00a0from TypeScript&#8217;s excess property checking. When we pass an object literal to something with an expected type, TypeScript will look for excess properties that weren&#8217;t declared in the expected type.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Options<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">width<\/span>?: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-c1\">height<\/span>?: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">a<\/span>: <span style=\"color: #267F99;\">Options<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">width<\/span>: <span style=\"color: #09885A;\">100<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-c1\">height<\/span>: <span style=\"color: #09885A;\">100<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span style=\"color: #a31515;\">\"data-blah\"<\/span>: <span style=\"color: #0000ff;\">true<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #148A14;\">\/\/ Error! 'data-blah' wasn't declared in 'Options'.<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">OptionsWithDataProps<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #267F99;\">Options<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ Permit any property starting with 'data-'.<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span class=\"pl-en\">optName<\/span>: <span style=\"color: #a31515;\">`data-<span class=\"pl-s1\"><span class=\"pl-kos\">${<\/span>string<span class=\"pl-kos\">}<\/span><\/span>`<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">unknown<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">b<\/span>: <span style=\"color: #267F99;\">OptionsWithDataProps<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">width<\/span>: <span style=\"color: #09885A;\">100<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-c1\">height<\/span>: <span style=\"color: #09885A;\">100<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span style=\"color: #a31515;\">\"data-blah\"<\/span>: <span style=\"color: #0000ff;\">true<\/span><span class=\"pl-kos\">,<\/span>       <span style=\"color: #148A14;\">\/\/ Works!<\/span>\r\n\r\n    <span style=\"color: #a31515;\">\"unknown-property\"<\/span>: <span style=\"color: #0000ff;\">true<\/span><span class=\"pl-kos\">,<\/span>  <span style=\"color: #148A14;\">\/\/ Error! 'unknown-property' wasn't declared in 'OptionsWithDataProps'.<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>A final note on index signatures is that they now permit union types, as long as they&#8217;re a union of infinite-domain primitive types &#8211; specifically:<\/p>\n<ul>\n<li><code>string<\/code><\/li>\n<li><code>number<\/code><\/li>\n<li><code>symbol<\/code><\/li>\n<li>template string patterns (e.g.\u00a0<code>`hello-${string}`<\/code>)<\/li>\n<\/ul>\n<p>An index signature whose argument is a union of these types will de-sugar into several different index signatures.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Data<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">optName<\/span>: <span style=\"color: #0000ff;\">string<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #0000ff;\">symbol<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">any<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Equivalent to<\/span>\r\n\r\n<span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Data<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">optName<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">any<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">optName<\/span>: <span style=\"color: #0000ff;\">symbol<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">any<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>For more details,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44512\">read up on the pull request<\/a><\/p>\n<h2 id=\"use-unknown-catch-variables\">Defaulting to the\u00a0<code>unknown<\/code>\u00a0Type in Catch Variables (<code>--useUnknownInCatchVariables<\/code>)<\/h2>\n<p>In JavaScript, any type of value can be thrown with\u00a0<code>throw<\/code>\u00a0and caught in a\u00a0<code>catch<\/code>\u00a0clause. Because of this, TypeScript historically typed catch clause variables as\u00a0<code>any<\/code>, and would not allow any other type annotation:<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">try<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ Who knows what this might throw...<\/span>\r\n    <span class=\"pl-en\">executeSomeThirdPartyCode<\/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 style=\"color: #0000ff;\">catch<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">err<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #148A14;\">\/\/ err: any<\/span>\r\n    <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">error<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">err<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">message<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ Allowed, because 'any'<\/span>\r\n    <span class=\"pl-s1\">err<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">thisWillProbablyFail<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ Allowed, because 'any' :(<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>Once TypeScript added the\u00a0<code>unknown<\/code>\u00a0type, it became clear that\u00a0<code>unknown<\/code>\u00a0was a better choice than\u00a0<code>any<\/code>\u00a0in\u00a0<code>catch<\/code>\u00a0clause variables for users who want the highest degree of correctness and type-safety, since it narrows better and forces us to test against arbitrary values. Eventually TypeScript 4.0 allowed users to specify an explicit type annotation of\u00a0<code>unknown<\/code>\u00a0(or\u00a0<code>any<\/code>) on each\u00a0<code>catch<\/code>\u00a0clause variable so that we could opt into stricter types on a case-by-case basis; however, for some, manually specifying\u00a0<code>: unknown<\/code>\u00a0on every\u00a0<code>catch<\/code>\u00a0clause was a chore.<\/p>\n<p>That&#8217;s why TypeScript 4.4 introduces a new flag called\u00a0<code>--useUnknownInCatchVariables<\/code>. This flag changes the default type of\u00a0<code>catch<\/code>\u00a0clause variables from\u00a0<code>any<\/code>\u00a0to\u00a0<code>unknown<\/code>.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">try<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">executeSomeThirdPartyCode<\/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 style=\"color: #0000ff;\">catch<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">err<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #148A14;\">\/\/ err: unknown<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ Error! Property 'message' does not exist on type 'unknown'.<\/span>\r\n    <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">error<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">err<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">message<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ Works! We can narrow 'err' from 'unknown' to 'Error'.<\/span>\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">err<\/span> <span style=\"color: #0000ff;\">instanceof<\/span> <span style=\"color: #267F99;\">Error<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">error<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">err<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">message<\/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>This flag is enabled under the\u00a0<code>--strict<\/code>\u00a0family of options. That means that if you check your code using\u00a0<code>--strict<\/code>, this option will automatically be turned on. You may end up with errors in TypeScript 4.4 such as<\/p>\n<div class=\"snippet-clipboard-content position-relative\">\n<pre><code>Property 'message' does not exist on type 'unknown'.\r\nProperty 'name' does not exist on type 'unknown'.\r\nProperty 'stack' does not exist on type 'unknown'.\r\n<\/code><\/pre>\n<\/div>\n<p>In cases where we don&#8217;t want to deal with an\u00a0<code>unknown<\/code>\u00a0variable in a\u00a0<code>catch<\/code>\u00a0clause, we can always add an explicit\u00a0<code>: any<\/code>\u00a0annotation so that we can opt\u00a0<em>out<\/em>\u00a0of stricter types.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">try<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">executeSomeThirdPartyCode<\/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 style=\"color: #0000ff;\">catch<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">err<\/span>: any<span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">error<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">err<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">message<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ Works again!<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>For more information, take a look at\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/41013\">the implementing pull request<\/a>.<\/p>\n<h2 id=\"exact-optional-property-types\">Exact Optional Property Types (<code>--exactOptionalPropertyTypes<\/code>)<\/h2>\n<p>In JavaScript, reading a\u00a0<em>missing<\/em>\u00a0property on an object produces the value\u00a0<code>undefined<\/code>. It&#8217;s also possible to\u00a0<em>have<\/em>\u00a0an actual property with the value\u00a0<code>undefined<\/code>. A lot of code in JavaScript tends to treat these situations the same way, and so initially TypeScript just interpreted every optional property as if a user had written\u00a0<code>undefined<\/code>\u00a0in the type. For example,<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">interface<\/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-c1\">age<\/span>?: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>was considered equivalent to<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">interface<\/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-c1\">age<\/span>?: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-c1\">|<\/span> <span style=\"color: #0000ff;\">undefined<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>What this meant is that a user could explicitly write\u00a0<code>undefined<\/code>\u00a0in place of\u00a0<code>age<\/code>.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\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\">p<\/span>: <span style=\"color: #267F99;\">Person<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">name<\/span>: <span style=\"color: #a31515;\">\"Daniel\"<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-c1\">age<\/span>: <span style=\"color: #0000ff;\">undefined<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #148A14;\">\/\/ This is okay by default.<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>So by default, TypeScript doesn&#8217;t distinguish between a present property with the value\u00a0<code>undefined<\/code>\u00a0and a missing property. While this works most of the time, not all code in JavaScript makes the same assumptions. Functions and operators like\u00a0<code>Object.assign<\/code>,\u00a0<code>Object.keys<\/code>, object spread (<code>{ ...obj }<\/code>), and\u00a0<code>for<\/code>&#8211;<code>in<\/code>\u00a0loops behave differently depending on whether or not a property actually exists on an object. In the case of our\u00a0<code>Person<\/code>\u00a0example, this could potentially lead to runtime errors if the\u00a0<code>age<\/code>\u00a0property was observed in a context where its presence was important.<\/p>\n<p>In TypeScript 4.4, the new flag\u00a0<code>--exactOptionalPropertyTypes<\/code>\u00a0specifies that optional property types should be interpreted exactly as written, meaning that\u00a0<code>| undefined<\/code>\u00a0is not added to the type:<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ With 'exactOptionalPropertyTypes' on:<\/span>\r\n<span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">p<\/span>: <span style=\"color: #267F99;\">Person<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">name<\/span>: <span style=\"color: #a31515;\">\"Daniel\"<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-c1\">age<\/span>: <span style=\"color: #0000ff;\">undefined<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #148A14;\">\/\/ Error! undefined isn't a number<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>This flag is not part of the\u00a0<code>--strict<\/code>\u00a0family and needs to be turned on explicitly if you&#8217;d like this behavior. It also requires\u00a0<code>--strictNullChecks<\/code>\u00a0to be enabled as well. We&#8217;ll be making updates to DefinitelyTyped and other definitions to try to make the transition as straightforward as possible, but you may encounter some friction with this depending on how your code is structured.<\/p>\n<p>For more information, you can\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43947\">take a look at the implementing pull request here<\/a>.<\/p>\n<h2 id=\"static-blocks\"><code>static<\/code>\u00a0Blocks in Classes<\/h2>\n<p>TypeScript 4.4 brings support for\u00a0<a href=\"https:\/\/github.com\/tc39\/proposal-class-static-block#ecmascript-class-static-initialization-blocks\"><code>static<\/code>\u00a0blocks in classes<\/a>, an upcoming ECMAScript feature that can help you write more-complex initialization code for static members.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\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;\">Foo<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">static<\/span> <span style=\"color: #267F99;\">Foo<\/span><span class=\"pl-kos\">.<\/span><\/span><span class=\"pl-c1\">count<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">0<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ This is a static block:<\/span>\r\n    <span style=\"color: #0000ff;\">static<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">someCondition<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n            <span style=\"color: #267F99;\">Foo<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-s1\">count<\/span><span class=\"pl-c1\">++<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span class=\"pl-kos\">}<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>These static blocks allow you to write a sequence of statements with their own scope that can access private fields within the containing class. That means that we can write initialization code with all the capabilities of writing statements, no leakage of variables, and full access to our class&#8217;s internals.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\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;\">Foo<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">static<\/span> #<span class=\"pl-c1\">count<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">0<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span style=\"color: #0000ff;\">get<\/span> <span class=\"pl-en\">count<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #267F99;\">Foo<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">count<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n\r\n    <span style=\"color: #0000ff;\">static<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">try<\/span> <span class=\"pl-kos\">{<\/span>\r\n            <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-c1\">lastInstances<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-en\">loadLastInstances<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n            <span style=\"color: #267F99;\">Foo<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">count<\/span> <span class=\"pl-c1\">+=<\/span> <span class=\"pl-c1\">lastInstances<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">length<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span class=\"pl-kos\">}<\/span>\r\n        <span style=\"color: #0000ff;\">catch<\/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>Without\u00a0<code>static<\/code>\u00a0blocks, writing the code above was possible, but often involved several different types of hacks that had to compromise in some way.<\/p>\n<p>Note that a class can have multiple\u00a0<code>static<\/code>\u00a0blocks, and they&#8217;re run in the same order in which they&#8217;re written.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ Prints:<\/span>\r\n<span style=\"color: #148A14;\">\/\/    1<\/span>\r\n<span style=\"color: #148A14;\">\/\/    2<\/span>\r\n<span style=\"color: #148A14;\">\/\/    3<\/span>\r\n<span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Foo<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">static<\/span> <span class=\"pl-c1\">prop<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">1<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">static<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-c1\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-s1\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #09885A;\"><span style=\"color: #267F99;\">Foo<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">count<\/span><\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n    <span style=\"color: #0000ff;\">static<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #09885A;\"><span style=\"color: #267F99;\">Foo<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">count<\/span><\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n    <span style=\"color: #0000ff;\">static<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #09885A;\"><span style=\"color: #267F99;\">Foo<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">count<\/span><\/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>We&#8217;d like to extend our thanks to\u00a0<a href=\"https:\/\/github.com\/Kingwl\">Wenlu Wang<\/a>\u00a0for TypeScript&#8217;s implementation of this feature. For more details, you can\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43370\">see that pull request here<\/a>.<\/p>\n<h2 id=\"tsc-help\"><code>tsc --help<\/code>\u00a0Updates and Improvements<\/h2>\n<p>TypeScript&#8217;s\u00a0<code>--help<\/code>\u00a0option has gotten a refresh! Thanks to work in part by\u00a0<a href=\"https:\/\/github.com\/ShuiRuTian\">Song Gao<\/a>, we&#8217;ve brought in changes to\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44409\">update the descriptions of our compiler options<\/a>\u00a0and\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44157\">restyle the\u00a0<code>--help<\/code>\u00a0menu<\/a>\u00a0with some colors and other visual separation. While we&#8217;re still iterating a bit on our styles to work well across platform default themes, you can get an idea of what it looks like by taking a look at\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/44074\">the original proposal thread<\/a>.<\/p>\n<h2 id=\"perf-improvements\">Performance Improvements<\/h2>\n<h3><a id=\"faster-declaration-emit\" class=\"anchor\" href=\"#faster-declaration-emit\" aria-hidden=\"true\"><\/a>Faster Declaration Emit<\/h3>\n<p>TypeScript now caches whether internal symbols are accessible in different contexts, along with how specific types should be printed. These changes can improve TypeScript&#8217;s general performance in code with fairly complex types, and is especially observed when emitting\u00a0<code>.d.ts<\/code>\u00a0files under the\u00a0<code>--declaration<\/code>\u00a0flag.<\/p>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43973\">See more details here<\/a>.<\/p>\n<h3><a id=\"faster-path-normalization\" class=\"anchor\" href=\"#faster-path-normalization\" aria-hidden=\"true\"><\/a>Faster Path Normalization<\/h3>\n<p>TypeScript often has to do several types of &#8220;normalization&#8221; on file paths to get them into a consistent format that the compiler can use everywhere. This involves things like replacing backslashes with slashes, or removing intermediate\u00a0<code>\/.\/<\/code>\u00a0and\u00a0<code>\/..\/<\/code>\u00a0segments of paths. When TypeScript has to operates over millions of these paths, these operations end up being a bit slow. In TypeScript 4.4, paths first undergo quick checks to see whether they need any normalization in the first place. These improvements together reduce project load time by 5-10% on bigger projects, and significantly more in massive projects that we&#8217;ve tested internally.<\/p>\n<p>For more details, you can\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44173\">view the PR for path segment normalization<\/a>\u00a0along with\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44100\">the PR for slash normalization<\/a>.<\/p>\n<h3><a id=\"faster-path-mapping\" class=\"anchor\" href=\"#faster-path-mapping\" aria-hidden=\"true\"><\/a>Faster Path Mapping<\/h3>\n<p>TypeScript now caches the way it constructs path-mappings (using the\u00a0<code>paths<\/code>\u00a0option in\u00a0<code>tsconfig.json<\/code>). For projects with several hundred mappings, the reduction is significant. You can see more\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44078\">on the change itself<\/a>.<\/p>\n<h3><a id=\"faster-incremental-builds-with---strict\" class=\"anchor\" href=\"#faster-incremental-builds-with---strict\" aria-hidden=\"true\"><\/a>Faster Incremental Builds with\u00a0<code>--strict<\/code><\/h3>\n<p>In what was effectively a bug, TypeScript would end up redoing type-checking work under\u00a0<code>--incremental<\/code>\u00a0compilations if\u00a0<code>--strict<\/code>\u00a0was on. This led to many builds being just as slow as if\u00a0<code>--incremental<\/code>\u00a0was turned off. TypeScript 4.4 fixes this, though the change has also been back-ported to TypeScript 4.3.<\/p>\n<p>See more\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44394\">here<\/a>.<\/p>\n<h3><a id=\"faster-source-map-generation-for-big-outputs\" class=\"anchor\" href=\"#faster-source-map-generation-for-big-outputs\" aria-hidden=\"true\"><\/a>Faster Source Map Generation for Big Outputs<\/h3>\n<p>TypeScript 4.4 adds an optimization for source map generation on extremely large output files. When building an older version of the TypeScript compiler, this results in around an 8% reduction in emit time.<\/p>\n<p>We&#8217;d like to extend our thanks to\u00a0<a href=\"https:\/\/github.com\/dmichon-msft\">David Michon<\/a>\u00a0who provided a\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44031\">simple and clean change<\/a>\u00a0to enable this performance win.<\/p>\n<h3><a id=\"faster---force-builds\" class=\"anchor\" href=\"#faster---force-builds\" aria-hidden=\"true\"><\/a>Faster\u00a0<code>--force<\/code>\u00a0Builds<\/h3>\n<p>When using\u00a0<code>--build<\/code>\u00a0mode on project references, TypeScript has to perform up-to-date checks to determine which files need to be rebuilt. When performing a\u00a0<code>--force<\/code>\u00a0build, however, that information is irrelevant since every project dependency will be rebuilt from scratch. In TypeScript 4.4,\u00a0<code>--force<\/code>\u00a0builds avoid those unnecessary steps and start a full build. See more about the change\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43666\">here<\/a>.<\/p>\n<h2 id=\"spelling-corrections-js\">Spelling Suggestions for JavaScript<\/h2>\n<p>TypeScript powers the JavaScript editing experience in editors like Visual Studio and Visual Studio Code. Most of the time, TypeScript tries to stay out of the way in JavaScript files; however, TypeScript often has a lot of information to make confident suggestions, and ways of surfacing suggestions that aren&#8217;t\u00a0<em>too<\/em>\u00a0invasive.<\/p>\n<p>That&#8217;s why TypeScript now issues spelling suggestions in plain JavaScript files &#8211; ones without\u00a0<code>\/\/ @ts-check<\/code>\u00a0or in a project with\u00a0<code>checkJs<\/code>\u00a0turned off. These are the same\u00a0<em>&#8220;Did you mean&#8230;?&#8221;<\/em>\u00a0suggestions that TypeScript files already have, and now they&#8217;re available in\u00a0<em>all<\/em>\u00a0JavaScript files in some form.<\/p>\n<p>These spelling suggestions can provide a subtle clue that your code is wrong. We managed to find a few bugs in existing code while testing this feature!<\/p>\n<p>For more details on this new feature,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44271\">take a look at the pull request<\/a>!<\/p>\n<h2 id=\"inlay-hints\">Inlay Hints<\/h2>\n<p>TypeScript 4.4 provides support for\u00a0<em>inlay hints<\/em>\u00a0which can help display useful information like parameter names and return types in your code. You can think of it as a sort of friendly &#8220;ghost text&#8221;.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/08\/inlayHints-4.4-rc-ghd.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"A preview of inlay hints in Visual Studio Code\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/08\/inlayHints-4.4-rc-ghd.png\" \/><\/a><\/p>\n<p>This feature was built by\u00a0<a href=\"https:\/\/github.com\/Kingwl\">Wenlu Wang<\/a>\u00a0whose\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/42089\">pull request<\/a>\u00a0has more details.<\/p>\n<p>Wenlu also contributed\u00a0<a href=\"https:\/\/github.com\/microsoft\/vscode\/pull\/113412\">the integration for inlay hints in Visual Studio Code<\/a>\u00a0which has shipped as\u00a0<a href=\"https:\/\/code.visualstudio.com\/updates\/v1_59#_typescript-44\" rel=\"nofollow\">part of the July 2021 (1.59) release<\/a>. If you&#8217;d like to try inlay hints out, make sure you&#8217;re using a recent\u00a0<a href=\"https:\/\/code.visualstudio.com\/updates\/v1_59\" rel=\"nofollow\">stable<\/a>\u00a0or\u00a0<a href=\"https:\/\/code.visualstudio.com\/insiders\/\" rel=\"nofollow\">insiders<\/a>\u00a0version of the editor. You can also modify when and where inlay hints get displayed in the settings.<\/p>\n<h2 id=\"auto-import-specifiers\">Auto-Imports Show True Paths in Completion Lists<\/h2>\n<p>When editors like Visual Studio Code show a completion list, completions which include auto-imports are displayed with a path to the given module; however, this path usually isn&#8217;t what TypeScript ends up placing in a module specifier. The path is usually something relative to the\u00a0<em>workspace<\/em>, meaning that if you&#8217;re importing from a package like\u00a0<code>moment<\/code>, you&#8217;ll often see a path like\u00a0<code>node_modules\/moment<\/code>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/08\/completion-import-labels-pre-4-4.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"A completion list containing unwieldy paths containing 'node_modules'. For example, the label for 'calendarFormat' is 'node_modules\/moment\/moment' instead of 'moment'.\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/08\/completion-import-labels-pre-4-4.png\" \/><\/a><\/p>\n<p>These paths end up being unwieldy and often misleading, especially given that the path that actually gets inserted into your file needs to consider Node&#8217;s\u00a0<code>node_modules<\/code>\u00a0resolution, path mappings, symlinks, and re-exports.<\/p>\n<p>That&#8217;s why with TypeScript 4.4, the completion item label now shows the\u00a0<em>actual<\/em>\u00a0module path that will be used for the import!<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/08\/completion-import-labels-4-4.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img decoding=\"async\" alt=\"A completion list containing clean paths with no intermediate 'node_modules'. For example, the label for 'calendarFormat' is 'moment' instead of 'node_modules\/moment\/moment'.\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/08\/completion-import-labels-4-4.png\" \/><\/a><\/p>\n<p>Since this calculation can be expensive, completion lists containing many auto-imports may fill in the final module specifiers in batches as you type more characters. It&#8217;s possible that you&#8217;ll still sometimes see the old workspace-relative path labels; however, as your editing experience &#8220;warms up&#8221;, they should get replaced with the actual path after another keystroke or two.<\/p>\n<h2 id=\"breaking-changes\">Breaking Changes<\/h2>\n<h3><a id=\"libdts-changes-for-typescript-44\" class=\"anchor\" href=\"#libdts-changes-for-typescript-44\" aria-hidden=\"true\"><\/a><code>lib.d.ts<\/code>\u00a0Changes for TypeScript 4.4<\/h3>\n<p>As with every TypeScript version, declarations for\u00a0<code>lib.d.ts<\/code>\u00a0(especially the declarations generated for web contexts), have changed. You can consult\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript-DOM-lib-generator\/issues\/1029#issuecomment-869224737\">our list of known\u00a0<code>lib.dom.d.ts<\/code>\u00a0changes<\/a>\u00a0to understand what is impacted.<\/p>\n<h3><a id=\"more-compliant-indirect-calls-for-imported-functions\" class=\"anchor\" href=\"#more-compliant-indirect-calls-for-imported-functions\" aria-hidden=\"true\"><\/a>More-Compliant Indirect Calls for Imported Functions<\/h3>\n<p>In earlier versions of TypeScript, calling an import from CommonJS, AMD, and other non-ES module systems would set the\u00a0<code>this<\/code>\u00a0value of the called function. Specifically, in the following example, when calling\u00a0<code>fooModule.foo()<\/code>, the\u00a0<code>foo()<\/code>\u00a0method will have\u00a0<code>fooModule<\/code>\u00a0set as the value of\u00a0<code>this<\/code>.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ Imagine this is our imported module, and it has an export named 'foo'.<\/span>\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">fooModule<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">this<\/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><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-s1\">fooModule<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>This is not the way exported functions in ECMAScript are supposed to work when we call them. That&#8217;s why TypeScript 4.4 intentionally discards the\u00a0<code>this<\/code>\u00a0value when calling imported functions, by using the following emit.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ Imagine this is our imported module, and it has an export named 'foo'.<\/span>\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">fooModule<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">this<\/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><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Notice we're actually calling '(0, fooModule.foo)' now, which is subtly different.<\/span>\r\n<span class=\"pl-kos\">(<\/span><span style=\"color: #09885A;\">0<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-s1\">fooModule<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">foo<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>You can\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44624\">read up more about the changes here<\/a>.<\/p>\n<h3><a id=\"using-unknown-in-catch-variables\" class=\"anchor\" href=\"#using-unknown-in-catch-variables\" aria-hidden=\"true\"><\/a>Using\u00a0<code>unknown<\/code>\u00a0in Catch Variables<\/h3>\n<p>Users running with the\u00a0<code>--strict<\/code>\u00a0flag may see new errors around\u00a0<code>catch<\/code>\u00a0variables being\u00a0<code>unknown<\/code>, especially if the existing code assumes only\u00a0<code>Error<\/code>\u00a0values have been caught. This often results in error messages such as:<\/p>\n<div class=\"snippet-clipboard-content position-relative\">\n<pre><code>Property 'message' does not exist on type 'unknown'.\r\nProperty 'name' does not exist on type 'unknown'.\r\nProperty 'stack' does not exist on type 'unknown'.\r\n<\/code><\/pre>\n<\/div>\n<p>To get around this, you can specifically add runtime checks to ensure that the thrown type matches your expected type. Otherwise, you can just use a type assertion, add an explicit\u00a0<code>: any<\/code>\u00a0to your catch variable, or turn off\u00a0<code>--useUnknownInCatchVariables<\/code>.<\/p>\n<h3><a id=\"broader-always-truthy-promise-checks\" class=\"anchor\" href=\"#broader-always-truthy-promise-checks\" aria-hidden=\"true\"><\/a>Broader Always-Truthy Promise Checks<\/h3>\n<p>In prior versions, TypeScript introduced &#8220;Always Truthy Promise checks&#8221; to catch code where an\u00a0<code>await<\/code>\u00a0may have been forgotten; however, the checks only applied to named declarations. That meant that while this code would correctly receive an error&#8230;<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">async<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">boolean<\/span><span class=\"pl-kos\">&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #0000ff;\">false<\/span><span class=\"pl-kos\">;<\/span>\r\n<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\">bar<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/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\">{<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">fooResult<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/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\">fooResult<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>        <span style=\"color: #148A14;\">\/\/ &lt;- error! :D<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #a31515;\">\"true\"<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n    <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #a31515;\">\"false\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>&#8230;the following code would not.<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">async<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">boolean<\/span><span class=\"pl-kos\">&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #0000ff;\">false<\/span><span class=\"pl-kos\">;<\/span>\r\n<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\">bar<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/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\">{<\/span>\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-en\">foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>            <span style=\"color: #148A14;\">\/\/ &lt;- no error :(<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #a31515;\">\"true\"<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n    <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #a31515;\">\"false\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>TypeScript 4.4 now flags both. For more information,\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/44491\">read up on the original change<\/a>.<\/p>\n<h3><a id=\"abstract-properties-do-not-allow-initializers\" class=\"anchor\" href=\"#abstract-properties-do-not-allow-initializers\" aria-hidden=\"true\"><\/a>Abstract Properties Do Not Allow Initializers<\/h3>\n<p>The following code is now an error because abstract properties may not have initializers:<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">abstract<\/span> <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">abstract<\/span> <span class=\"pl-c1\">prop<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">1<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #148A14;\">\/\/       ~~~~<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ Property 'prop' cannot have an initializer because it is marked abstract.<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<div class=\"zeroclipboard-container position-absolute right-0 top-0\"><\/div>\n<\/div>\n<p>Instead, you may only specify a type for the property:<\/p>\n<div class=\"highlight highlight-source-ts position-relative\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">abstract<\/span> <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">abstract<\/span> <span class=\"pl-c1\">prop<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<h2><a id=\"whats-next\" class=\"anchor\" href=\"#whats-next\" aria-hidden=\"true\"><\/a>What&#8217;s Next?<\/h2>\n<p>We&#8217;re planning on our stable release of TypeScript 4.4 in the next few weeks, which you can track on the\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/44237\">4.4 Iteration plan<\/a>. We want to make sure that 4.4 is a solid stable release, so\u00a0<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/new\/choose\">let us know what you think<\/a>!<\/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.4! Between now and the stable release of TypeScript 4.4, 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-3042","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.4! Between now and the stable release of TypeScript 4.4, 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\/3042","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=3042"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3042\/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=3042"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=3042"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=3042"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}