{"id":3554,"date":"2022-09-23T12:03:24","date_gmt":"2022-09-23T20:03:24","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=3554"},"modified":"2022-09-23T12:52:17","modified_gmt":"2022-09-23T20:52:17","slug":"announcing-typescript-4-9-beta","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-9-beta\/","title":{"rendered":"Announcing TypeScript 4.9 Beta"},"content":{"rendered":"<p>Today we&#8217;re announcing our beta release of TypeScript 4.9!<\/p>\n<p>To get started using the beta, 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><code>npm install -D typescript@beta\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-49beta\">Downloading for Visual Studio 2022\/2019<\/a><\/li>\n<li>Following directions for <a href=\"https:\/\/code.visualstudio.com\/Docs\/languages\/typescript#_using-newer-typescript-versions\">Visual Studio Code<\/a>.<\/li>\n<\/ul>\n<p>Here&#8217;s a quick list of what&#8217;s new in TypeScript 4.9!<\/p>\n<ul>\n<li><a href=\"#hamilton\">The <code>satisfies<\/code> Operator<\/a><\/li>\n<li><a href=\"#in-narrowing\">Unlisted Property Narrowing with the <code>in<\/code> Operator<\/a><\/li>\n<li><a href=\"#bye-bye-batman\">Checks For Equality on <code>NaN<\/code><\/a><\/li>\n<li><a href=\"#file-watching-changes\">File-Watching Now Uses File System Events<\/a><\/li>\n<li><a href=\"#correctness-changes\">Correctness Fixes and Breaking Changes<\/a><\/li>\n<\/ul>\n<h2><a name=\"hamilton\"><\/a> The <code>satisfies<\/code> Operator<\/h2>\n<p>TypeScript developers are often faced with a dilemma: we want to ensure that some expression <em>matches<\/em> some type, but also want to keep the <em>most specific<\/em> type of that expression for inference purposes.<\/p>\n<p>For example:<\/p>\n<pre><code>\/\/ Each property can be a string or an RGB tuple.\r\nconst palette = {\r\n    red: [255, 0, 0],\r\n    green: &quot;#00ff00&quot;,\r\n    bleu: [0, 0, 255]\r\n\/\/  ^^^^ sacr\u00e9 bleu - we've made a typo!\r\n};\r\n\r\n\/\/ We want to be able to use array methods on 'red'...\r\nconst redComponent = palette.red.at(0);\r\n\r\n\/\/ or string methods on 'green'...\r\nconst greenNormalized = palette.green.toUpperCase();\r\n<\/code><\/pre>\n<p>Notice that we&#8217;ve written <code>bleu<\/code>, whereas we probably should have written <code>blue<\/code>.\nWe could try to catch that <code>bleu<\/code> typo by using a type annotation on <code>palette<\/code>, but we&#8217;d lose the information about each property.<\/p>\n<pre><code>type Colors = &quot;red&quot; | &quot;green&quot; | &quot;blue&quot;;\r\n\r\ntype RGB = [red: number, green: number, blue: number];\r\n\r\nconst palette: Record&lt;Colors, string | RGB&gt; = {\r\n    red: [255, 0, 0],\r\n    green: &quot;#00ff00&quot;,\r\n    bleu: [0, 0, 255]\r\n\/\/  ~~~~ The typo is now correctly detected\r\n};\r\n\r\n\/\/ But we now have an undesirable error here - 'palette.red' &quot;could&quot; be a string.\r\nconst redComponent = palette.red.at(0);\r\n<\/code><\/pre>\n<p>The new <code>satisfies<\/code> operator lets us validate that the type of an expression matches some type, without changing the resulting type of that expression.\nAs an example, we could use <code>satisfies<\/code> to validate that all the properties of <code>palette<\/code> are compatible with <code>string | number[]<\/code>:<\/p>\n<pre><code>type Colors = &quot;red&quot; | &quot;green&quot; | &quot;blue&quot;;\r\n\r\ntype RGB = [red: number, green: number, blue: number];\r\n\r\nconst palette = {\r\n    red: [255, 0, 0],\r\n    green: &quot;#00ff00&quot;,\r\n    bleu: [0, 0, 255]\r\n\/\/  ~~~~ The typo is now caught!\r\n} satisfies Record&lt;Colors, string | RGB&gt;;\r\n\r\n\/\/ Both of these methods are still accessible!\r\nconst redComponent = palette.red.at(0);\r\nconst greenNormalized = palette.green.toUpperCase();\r\n<\/code><\/pre>\n<p><code>satisfies<\/code> can be used to catch lots of possible errors.\nFor example, we could ensure that an object has <em>all<\/em> the keys of some type, but no more:<\/p>\n<pre><code>type Colors = &quot;red&quot; | &quot;green&quot; | &quot;blue&quot;;\r\n\r\n\/\/ Ensure that we have exactly the keys from 'Colors'.\r\nconst favoriteColors = {\r\n    &quot;red&quot;: &quot;yes&quot;,\r\n    &quot;green&quot;: false,\r\n    &quot;blue&quot;: &quot;kinda&quot;,\r\n    &quot;platypus&quot;: false\r\n\/\/  ~~~~~~~~~~ error - &quot;platypus&quot; was never listed in 'Colors'.\r\n} satisfies Record&lt;Colors, unknown&gt;;\r\n\r\n\/\/ All the information about the 'red', 'green', and 'blue' properties are retained.\r\nconst g: boolean = favoriteColors.green;\r\n<\/code><\/pre>\n<p>Maybe we don&#8217;t care about if the property names match up somehow, but we do care about the types of each property.\nIn that case, we can also ensure that all of an object&#8217;s property values conform to some type.<\/p>\n<pre><code>type RGB = [red: number, green: number, blue: number];\r\n\r\nconst palette = {\r\n    red: [255, 0, 0],\r\n    green: &quot;#00ff00&quot;,\r\n    blue: [0, 0]\r\n    \/\/    ~~~~~~ error!\r\n} satisfies Record&lt;string, string | RGB&gt;;\r\n\r\n\/\/ Information about each property is still maintained.\r\nconst redComponent = palette.red.at(0);\r\nconst greenNormalized = palette.green.toUpperCase();\r\n<\/code><\/pre>\n<p>For more examples, you can see the <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/47920\">issue proposing this<\/a> and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/46827\">the implementing pull request<\/a>.\nWe&#8217;d like to thank <a href=\"https:\/\/github.com\/a-tarasyuk\">Oleksandr Tarasiuk<\/a> who implemented and iterated on this feature with us.<\/p>\n<h2><a name=\"in-narrowing\"><\/a> Unlisted Property Narrowing with the <code>in<\/code> Operator<\/h2>\n<p>As developers, we often need to deal with values that aren&#8217;t fully known at runtime.\nIn fact, we often don&#8217;t know if properties exist, whether we&#8217;re getting a response from a server or reading a configuration file.\nJavaScript&#8217;s <code>in<\/code> operator can check whether a property\nexists on an object.<\/p>\n<p>Previously, TypeScript allowed us to narrow away any types that don&#8217;t explicitly list a property.<\/p>\n<pre><code>interface RGB {\r\n    red: number;\r\n    green: number;\r\n    blue: number;\r\n}\r\n\r\ninterface HSV {\r\n    hue: number;\r\n    saturation: number;\r\n    value: number;\r\n}\r\n\r\nfunction setColor(color: RGB | HSV) {\r\n    if (&quot;hue&quot; in color) {\r\n        \/\/ 'color' now has the type HSV\r\n    }\r\n    \/\/ ...\r\n}\r\n<\/code><\/pre>\n<p>Here, the type <code>RGB<\/code> didn&#8217;t list the <code>hue<\/code> and got narrowed away, and leaving us with the type <code>HSV<\/code>.<\/p>\n<p>But what about examples where no type listed a given property?\nIn those cases, the language didn&#8217;t help us much.\nLet&#8217;s take the following example in JavaScript:<\/p>\n<pre><code>function tryGetPackageName(context) {\r\n    const packageJSON = context.packageJSON;\r\n    \/\/ Check to see if we have an object.\r\n    if (packageJSON &amp;&amp; typeof packageJSON === &quot;object&quot;) {\r\n        \/\/ Check to see if it has a string name property.\r\n        if (&quot;name&quot; in packageJSON &amp;&amp; typeof packageJSON.name === &quot;string&quot;) {\r\n            return packageJSON.name;\r\n        }\r\n    }\r\n\r\n    return undefined;\r\n}\r\n<\/code><\/pre>\n<p>Rewriting this to canonical TypeScript would just be a matter of defining and using a type for <code>context<\/code>;\nhowever, picking a safe type like <code>unknown<\/code> for the <code>packageJSON<\/code> property would cause issues in older versions of TypeScript.<\/p>\n<pre><code>interface Context {\r\n    packageJSON: unknown;\r\n}\r\n\r\nfunction tryGetPackageName(context: Context) {\r\n    const packageJSON = context.packageJSON;\r\n    \/\/ Check to see if we have an object.\r\n    if (packageJSON &amp;&amp; typeof packageJSON === &quot;object&quot;) {\r\n        \/\/ Check to see if it has a string name property.\r\n        if (&quot;name&quot; in packageJSON &amp;&amp; typeof packageJSON.name === &quot;string&quot;) {\r\n        \/\/                                              ~~~~\r\n        \/\/ error! Property 'name' does not exist on type 'object.\r\n            return packageJSON.name;\r\n        \/\/                     ~~~~\r\n        \/\/ error! Property 'name' does not exist on type 'object.\r\n        }\r\n    }\r\n\r\n    return undefined;\r\n}\r\n<\/code><\/pre>\n<p>This is because while the type of <code>packageJSON<\/code> was narrowed from <code>unknown<\/code> to <code>object<\/code>, the <code>in<\/code> operator strictly narrowed to types that actually defined the property being checked.\nAs a result, the type of <code>packageJSON<\/code> remained <code>object<\/code>.<\/p>\n<p>TypeScript 4.9 makes the <code>in<\/code> operator a little bit more powerful when narrowing types that <em>don&#8217;t<\/em> list the property at all.\nInstead of leaving them as-is, the language will intersect their types with <code>Record&lt;&quot;property-key-being-checked&quot;, unknown&gt;<\/code>.<\/p>\n<p>So in our example, <code>packageJSON<\/code> will have its type narrowed from <code>unknown<\/code> to <code>object<\/code> to <code>object &amp; Record&lt;&quot;name&quot;, unknown&gt;<\/code>\nThat allows us to access <code>packageJSON.name<\/code> directly and narrow that independently.<\/p>\n<pre><code>interface Context {\r\n    packageJSON: unknown;\r\n}\r\n\r\nfunction tryGetPackageName(context: Context): string | undefined {\r\n    const packageJSON = context.packageJSON;\r\n    \/\/ Check to see if we have an object.\r\n    if (packageJSON &amp;&amp; typeof packageJSON === &quot;object&quot;) {\r\n        \/\/ Check to see if it has a string name property.\r\n        if (&quot;name&quot; in packageJSON &amp;&amp; typeof packageJSON.name === &quot;string&quot;) {\r\n            \/\/ Just works!\r\n            return packageJSON.name;\r\n        }\r\n    }\r\n\r\n    return undefined;\r\n}\r\n<\/code><\/pre>\n<p>TypeScript 4.9 also tightens up a few checks around how <code>in<\/code> is used, ensuring that the left side is assignable to the type <code>string | number | symbol<\/code>, and the right side is assignable to <code>object<\/code>.\nThis helps check that we&#8217;re using valid property keys, and not accidentally checking primitives.<\/p>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50666\">read the implementing pull request<\/a><\/p>\n<h2><a name=\"bye-bye-batman\"><\/a> Checks For Equality on <code>NaN<\/code><\/h2>\n<p>A major gotcha for JavaScript developers is checking against the value <code>NaN<\/code> using the built-in equality operators.<\/p>\n<p>For some background, <code>NaN<\/code> is a special numeric value that stands for &quot;Not a Number&quot;.\nNothing is ever equal to <code>NaN<\/code> &#8211; even <code>NaN<\/code>!<\/p>\n<pre><code>console.log(NaN == 0)  \/\/ false\r\nconsole.log(NaN === 0) \/\/ false\r\n\r\nconsole.log(NaN == NaN)  \/\/ false\r\nconsole.log(NaN === NaN) \/\/ false\r\n<\/code><\/pre>\n<p>But at least symmetrically <em>everything<\/em> is always not-equal to <code>NaN<\/code>.<\/p>\n<pre><code>console.log(NaN != 0)  \/\/ true\r\nconsole.log(NaN !== 0) \/\/ true\r\n\r\nconsole.log(NaN != NaN)  \/\/ true\r\nconsole.log(NaN !== NaN) \/\/ true\r\n<\/code><\/pre>\n<p>This technically isn&#8217;t a JavaScript-specific problem, since any language that contains IEEE-754 floats has the same behavior;\nbut JavaScript&#8217;s primary numeric type is a floating point number, and number parsing in JavaScript can often result in <code>NaN<\/code>.\nIn turn, checking against <code>NaN<\/code> ends up being fairly common, and the correct way to do so is to use <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Number\/isNaN\"><code>Number.isNaN<\/code><\/a> &#8211; <em>but<\/em> as we mentioned, lots of people accidentally end up checking with <code>someValue === NaN<\/code> instead.<\/p>\n<p>TypeScript now errors on direct comparisons against <code>NaN<\/code>, and will suggest using some variation of <code>Number.isNaN<\/code> instead.<\/p>\n<pre><code>function validate(someValue: number) {\r\n    return someValue !== NaN;\r\n    \/\/     ~~~~~~~~~~~~~~~~~\r\n    \/\/ error: This condition will always return 'true'.\r\n    \/\/        Did you mean '!Number.isNaN(someValue)'?\r\n}\r\n<\/code><\/pre>\n<p>We believe that this change should strictly help catch beginner errors, similar to how TypeScript currently issues errors on comparisons against object and array literals.<\/p>\n<p>We&#8217;d like to extend our thanks to <a href=\"https:\/\/github.com\/a-tarasyuk\">Oleksandr Tarasiuk<\/a> who <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50626\">contributed this check<\/a>.<\/p>\n<h2><a name=\"file-watching-changes\"><\/a> File-Watching Now Uses File System Events<\/h2>\n<p>In earlier versions, TypeScript leaned heavily on <em>polling<\/em> for watching individual files.\nUsing a polling strategy meant checking the state of a file periodically for updates.\nOn Node.js, <a href=\"https:\/\/nodejs.org\/docs\/latest-v18.x\/api\/fs.html#fswatchfilefilename-options-listener\"><code>fs.watchFile<\/code><\/a> is the built-in way to get a polling file-watcher.\nWhile polling tends to be more predictable across platforms and file systems, it means that your CPU has to periodically get interrupted and check for updates to the file, even when nothing&#8217;s changed.\nFor a few dozen files, this might not be noticeable;\nbut on a bigger project with lots of files &#8211; or lots of files in <code>node_modules<\/code> &#8211; this can become a resource hog.<\/p>\n<p>Generally speaking, a better approach is to use file system events.\nInstead of polling, we can announce that we&#8217;re interested in updates of specific files and provide a callback for when those files <em>actually do<\/em> change.\nMost modern platforms in use provide facilities and APIs like <code>CreateIoCompletionPort<\/code>, <code>kqueue<\/code>, <code>epoll<\/code>, and <code>inotify<\/code>.\nNode.js mostly abstracts these away by providing <a href=\"https:\/\/nodejs.org\/docs\/latest-v18.x\/api\/fs.html#fswatchfilename-options-listener\"><code>fs.watch<\/code><\/a>.\nFile system events usually work great, but there are <a href=\"https:\/\/nodejs.org\/docs\/latest-v18.x\/api\/fs.html#caveats\">lots of caveats<\/a> to using them, and in turn, to using the <code>fs.watch<\/code> API.\nA watcher needs to be careful to consider <a href=\"https:\/\/nodejs.org\/docs\/latest-v18.x\/api\/fs.html#inodes\">inode watching<\/a>, <a href=\"https:\/\/nodejs.org\/docs\/latest-v18.x\/api\/fs.html#availability\">unavailability on certain file systems<\/a> (e.g.networked file systems), whether recursive file watching is available, whether directory renames trigger events, and even file watcher exhaustion!\nIn other words, it&#8217;s not quite a free lunch, especially if you&#8217;re looking for something cross-platform.<\/p>\n<p>As a result, our default was to pick the lowest common denominator: polling.\nNot always, but most of the time.<\/p>\n<p>Over time, we&#8217;ve provided the means to <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/configuring-watch.html\">choose other file-watching strategies<\/a>.\nThis allowed us to get feedback and harden our file-watching implementation against most of these platform-specific gotchas.\nAs TypeScript has needed to scale to larger codebases, and has improved in this area, we felt swapping to file system events as the default would be a worthwhile investment.<\/p>\n<p>In TypeScript 4.9, file watching is powered by file system events by default, only falling back to polling if we fail to set up event-based watchers.\nFor most developers, this should provide a much less resource-intensive experience when running in <code>--watch<\/code> mode, or running with a TypeScript-powered editor like Visual Studio or VS Code.<\/p>\n<p><a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/configuring-watch.html\">The way file-watching works can still be configured<\/a> through environment variables and <code>watchOptions<\/code> &#8211; and <a href=\"https:\/\/code.visualstudio.com\/docs\/getstarted\/settings#:~:text=typescript%2etsserver%2ewatchOptions\">some editors like VS Code can support <code>watchOptions<\/code> independently<\/a>.\nDevelopers using more exotic set-ups where source code resides on a networked file systems (like NFS and SMB) may need to opt back into the older behavior; though if a server has reasonable processing power, it might just be better to enable SSH and run TypeScript remotely so that it has direct local file access.\nVS Code has plenty of <a href=\"https:\/\/marketplace.visualstudio.com\/search?term=remote&amp;target=VSCode&amp;category=All%20categories&amp;sortBy=Relevance\">remote extensions<\/a> to make this easier.<\/p>\n<p>You can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50366\">read up more on this change on GitHub<\/a>.<\/p>\n<h2><a name=\"correctness-changes\"><\/a> Correctness Fixes and Breaking Changes<\/h2>\n<h3><code>lib.d.ts<\/code> Updates<\/h3>\n<p>While TypeScript strives to avoid major breaks, even small changes in the built-in libraries can cause issues.\nWe don&#8217;t expect major breaks as a result of DOM and <code>lib.d.ts<\/code> updates, but there may be some small ones.<\/p>\n<h3>Better Types for <code>Promise.resolve<\/code><\/h3>\n<p><code>Promise.resolve<\/code> now uses the <code>Awaited<\/code> type to unwrap Promise-like types passed to it.\nThis means that it more often returns the right <code>Promise<\/code> type, but that improved type can break existing code if it was expecting <code>any<\/code> or <code>unknown<\/code> instead of a <code>Promise<\/code>.\nFor more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/33074\">see the original change<\/a>.<\/p>\n<h3>JavaScript Emit No Longer Elides Imports<\/h3>\n<p>When TypeScript first supported type-checking and compilation for JavaScript, it accidentally supported a feature called import elision.\nIn short, if an import is not used as a value, or the compiler can detect that the import doesn&#8217;t refer to a value at runtime, the compiler will drop the import during emit.<\/p>\n<p>This behavior was questionable, especially the detection of whether the import doesn&#8217;t refer to a value, since it means that TypeScript has to trust sometimes-inaccurate declaration files.\nIn turn, TypeScript now preserves imports in JavaScript files.<\/p>\n<pre><code>\/\/ Input:\r\nimport { someValue, SomeClass } from &quot;some-module&quot;;\r\n\r\n\/** @type {SomeClass} *\/\r\nlet val = someValue;\r\n\r\n\/\/ Previous Output:\r\nimport { someValue } from &quot;some-module&quot;;\r\n\r\n\/** @type {SomeClass} *\/\r\nlet val = someValue;\r\n\r\n\/\/ Current Output:\r\nimport { someValue, SomeClass } from &quot;some-module&quot;;\r\n\r\n\/** @type {SomeClass} *\/\r\nlet val = someValue;\r\n<\/code><\/pre>\n<p>More information is available at <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50404\">the implementing change<\/a>.<\/p>\n<h3><code>exports<\/code> is Prioritized Over <code>typesVersions<\/code><\/h3>\n<p>Previously, TypeScript incorrectly prioritized the <code>typesVersions<\/code> field over the <code>exports<\/code> field when resolving through a <code>package.json<\/code> under <code>--moduleResolution node16<\/code>.\nIf this change impacts your library, you may need to add <code>types@<\/code> version selectors in your <code>package.json<\/code>&#8216;s <code>exports<\/code> field.<\/p>\n<pre><code>  {\r\n      &quot;type&quot;: &quot;module&quot;,\r\n      &quot;main&quot;: &quot;.\/dist\/main.js&quot;\r\n      &quot;typesVersions&quot;: {\r\n          &quot;&lt;4.8&quot;: { &quot;.&quot;: [&quot;4.8-types\/main.d.ts&quot;] },\r\n          &quot;*&quot;: { &quot;.&quot;: [&quot;modern-types\/main.d.ts&quot;] }\r\n      },\r\n      &quot;exports&quot;: {\r\n          &quot;.&quot;: {\r\n+             &quot;types@&lt;4.8&quot;: &quot;4.8-types\/main.d.ts&quot;,\r\n+             &quot;types&quot;: &quot;modern-types\/main.d.ts&quot;,\r\n              &quot;import&quot;: &quot;.\/dist\/main.js&quot;\r\n          }\r\n      }\r\n  }\r\n<\/code><\/pre>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50890\">see this pull request<\/a>.<\/p>\n<h2><code>substitute<\/code> Replaced With <code>constraint<\/code> on <code>SubstitutionType<\/code>s<\/h2>\n<p>As part of an optimization on substitution types, <code>SubstitutionType<\/code> objects no longer contain the <code>substitute<\/code> property representing the effective substitution (usually an intersection of the base type and the implicit constraint) &#8211; instead, they just contain the <code>constraint<\/code> property.<\/p>\n<p>For more details, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50397\">read more on the original pull request<\/a>.<\/p>\n<h2>What&#8217;s Next<\/h2>\n<p>Over the next few weeks, we&#8217;ll be continuing development on TypeScript 4.9, eventually shipping a release candidate and then a final release.\nThat work will primarily include bug fixes, polish, and low-risk editor-oriented features.\nSo while the TypeScript beta represents a mostly-feature-complete point of the release cycle, the best way to get an idea of the state of TypeScript 4.9 is to <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\">try a nightly build<\/a>!<\/p>\n<p>And if you&#8217;re interested in planning around the release, be sure to <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/50457\">keep an eye on our iteration plan<\/a>.\nIn the meantime, please try out the beta today and let us know what you think!<\/p>\n<p>Happy Hacking!<\/p>\n<p>&#8211; Daniel Rosenwasser and the TypeScript Team<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re announcing our beta release of TypeScript 4.9! To get started using the beta, you can get it through NuGet, or- use npm with the following command: npm install -D typescript@beta You can also get editor support by Downloading for Visual Studio 2022\/2019 Following directions for Visual Studio Code. Here&#8217;s a quick list of [&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-3554","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-typescript"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re announcing our beta release of TypeScript 4.9! To get started using the beta, you can get it through NuGet, or- use npm with the following command: npm install -D typescript@beta You can also get editor support by Downloading for Visual Studio 2022\/2019 Following directions for Visual Studio Code. Here&#8217;s a quick list of [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3554","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=3554"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3554\/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=3554"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=3554"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=3554"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}