{"id":4001,"date":"2023-08-09T12:13:55","date_gmt":"2023-08-09T20:13:55","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=4001"},"modified":"2023-08-10T11:04:37","modified_gmt":"2023-08-10T19:04:37","slug":"announcing-typescript-5-2-rc","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-2-rc\/","title":{"rendered":"Announcing TypeScript 5.2 RC"},"content":{"rendered":"<p>Today we&#8217;re excited to announce our Release Candidate of TypeScript 5.2!\nBetween now and the stable release of TypeScript 5.2, we expect no further changes apart from critical bug fixes.<\/p>\n<p>To get started using the RC, you can get it <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.TypeScript.MSBuild\">through NuGet<\/a>, or through npm with the following command:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #000000;\">npm install -D typescript@rc<\/span>\r\n<\/code><\/pre>\n<p>Here&#8217;s a quick list of what&#8217;s new in TypeScript 5.2!<\/p>\n<ul>\n<li><a href=\"#using-declarations-and-explicit-resource-management\"><code>using<\/code> Declarations and Explicit Resource Management<\/a><\/li>\n<li><a href=\"#decorator-metadata\">Decorator Metadata<\/a><\/li>\n<li><a href=\"#named-and-anonymous-tuple-elements\">Named and Anonymous Tuple Elements<\/a><\/li>\n<li><a href=\"#easier-method-usage-for-unions-of-arrays\">Easier Method Usage for Unions of Arrays<\/a><\/li>\n<li><a href=\"#type-only-import-paths-with-typescript-implementation-file-extensions\">Type-Only Import Paths with TypeScript Implementation File Extensions<\/a><\/li>\n<li><a href=\"#comma-completions-for-object-members\">Comma Completions for Object Members<\/a><\/li>\n<li><a href=\"#inline-variable-refactoring\">Inline Variable Refactoring<\/a><\/li>\n<li><a href=\"#optimized-checks-for-ongoing-type-compatibility\">Optimized Checks for Ongoing Type Compatibility<\/a><\/li>\n<li><a href=\"#breaking-changes-and-correctness-fixes\">Breaking Changes and Correctness Fixes<\/a><\/li>\n<\/ul>\n<h2>What&#8217;s New Since the Beta?<\/h2>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-2-beta\/\">Since the Beta<\/a>, we&#8217;ve added <a href=\"#optimized-checks-for-ongoing-type-compatibility\">a type-checking optimization<\/a> and <a href=\"#type-only-import-paths-with-typescript-implementation-file-extensions\">made it possible to reference the paths of TypeScript implementation files in type-only imports<\/a>.<\/p>\n<h2><code>using<\/code> Declarations and Explicit Resource Management<\/h2>\n<p>TypeScript 5.2 adds support for the upcoming <a href=\"https:\/\/github.com\/tc39\/proposal-explicit-resource-management\">Explicit Resource Management<\/a> feature in ECMAScript.\nLet&#8217;s explore some of the motivations and understand what the feature brings us.<\/p>\n<p>It&#8217;s common to need to do some sort of &quot;clean-up&quot; after creating an object.\nFor example, you might need to close network connections, delete temporary files, or just free up some memory.<\/p>\n<p>Let&#8217;s imagine a function that creates a temporary file, reads and writes to it for various operations, and then closes and deletes it.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #AF00DB;\">import<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">*<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #AF00DB;\">as<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #AF00DB;\">from<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">&quot;fs&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doSomeWork<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">path<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #A31515;\">&quot;.some_temp_file&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">file<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">openSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;w+&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ use file...<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ Close the file and delete it.<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">closeSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">file<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">unlinkSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>This is fine, but what happens if we need to perform an early exit?<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doSomeWork<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">path<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #A31515;\">&quot;.some_temp_file&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">file<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">openSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;w+&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ use file...<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #795E26;\">someCondition<\/span><span style=\"color: #000000;\">()) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ do some more work...<\/span>\r\n\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ Close the file and delete it.<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">closeSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">file<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">unlinkSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ Close the file and delete it.<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">closeSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">file<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">unlinkSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>We&#8217;re starting to see some duplication of clean-up which can be easy to forget.\nWe&#8217;re also not guaranteed to close and delete the file if an error gets thrown.\nThis could be solved by wrapping this all in a <code>try<\/code>\/<code>finally<\/code> block.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doSomeWork<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">path<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #A31515;\">&quot;.some_temp_file&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">file<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">openSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;w+&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">try<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ use file...<\/span>\r\n\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #795E26;\">someCondition<\/span><span style=\"color: #000000;\">()) {<\/span>\r\n<span style=\"color: #000000;\">            <\/span><span style=\"color: #008000;\">\/\/ do some more work...<\/span>\r\n<span style=\"color: #000000;\">            <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">        }<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">finally<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ Close the file and delete it.<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">closeSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">file<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">unlinkSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>While this is more robust, it&#8217;s added quite a bit of &quot;noise&quot; to our code.\nThere are also other foot-guns we can run into if we start adding more clean-up logic to our <code>finally<\/code> block \u2014 for example, exceptions preventing other resources from being disposed.\nThis is what the <a href=\"https:\/\/github.com\/tc39\/proposal-explicit-resource-management\">explicit resource management<\/a> proposal aims to solve.\nThe key idea of the proposal is to support resource disposal \u2014 this clean-up work we&#8217;re trying to deal with \u2014 as a first class idea in JavaScript.<\/p>\n<p>This starts by adding a new built-in <code>symbol<\/code> called <code>Symbol.dispose<\/code>, and we can create objects with methods named by <code>Symbol.dispose<\/code>.\nFor convenience, TypeScript defines a new global type called <code>Disposable<\/code> which describes these.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">class<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">TempFile<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">implements<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Disposable<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">#path<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">#handle<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">number<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">constructor<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">#path<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">#handle<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">openSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;w+&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ other methods<\/span>\r\n\r\n<span style=\"color: #000000;\">    [<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">dispose<\/span><span style=\"color: #000000;\">]() {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ Close the file and delete it.<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">closeSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">#handle<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">unlinkSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">#path<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>Later on we can call those methods.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doSomeWork<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">file<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">TempFile<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;.some_temp_file&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">try<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ ...<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">finally<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">file<\/span><span style=\"color: #000000;\">[<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">dispose<\/span><span style=\"color: #000000;\">]();<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>Moving the clean-up logic to <code>TempFile<\/code> itself doesn&#8217;t buy us much;\nwe&#8217;ve basically just moved all the clean-up work from the <code>finally<\/code> block into a method, and that&#8217;s always been possible.\nBut having a well-known &quot;name&quot; for this method means that JavaScript can build other features on top of it.<\/p>\n<p>That brings us to the first star of the feature: <code>using<\/code> declarations!\n<code>using<\/code> is a new keyword that lets us declare new fixed bindings, kind of like <code>const<\/code>.\nThe key difference is that variables declared with <code>using<\/code> get their <code>Symbol.dispose<\/code> method called at the end of the scope!<\/p>\n<p>So we could simply have written our code like this:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doSomeWork<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">file<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">TempFile<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;.some_temp_file&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ use file...<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #795E26;\">someCondition<\/span><span style=\"color: #000000;\">()) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ do some more work...<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>Check it out \u2014 no <code>try<\/code>\/<code>finally<\/code> blocks!\nAt least, none that we see.\nFunctionally, that&#8217;s exactly what <code>using<\/code> declarations will do for us, but we don&#8217;t have to deal with that.<\/p>\n<p>You might be familiar with <a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/proposals\/csharp-8.0\/using\"><code>using<\/code> declarations in C#<\/a>, <a href=\"https:\/\/docs.python.org\/3\/reference\/compound_stmts.html#the-with-statement\"><code>with<\/code> statements in Python<\/a>, or <a href=\"https:\/\/docs.oracle.com\/javase\/tutorial\/essential\/exceptions\/tryResourceClose.html\"><code>try<\/code>-with-resource declarations in Java<\/a>.\nThese are all similar to JavaScript&#8217;s new <code>using<\/code> keyword, and provide a similar explicit way to perform a &quot;tear-down&quot; of an object at the end of a scope.<\/p>\n<p><code>using<\/code> declarations do this clean-up at the very end of their containing scope or right before an &quot;early return&quot; like a <code>return<\/code> or a <code>throw<\/code>n error.\nThey also dispose in a first-in-last-out order like a stack.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">id<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">): <\/span><span style=\"color: #267F99;\">Disposable<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">`Creating <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">id<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #000000;\">);<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        [<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">dispose<\/span><span style=\"color: #000000;\">]() {<\/span>\r\n<span style=\"color: #000000;\">            <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">`Disposing <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">id<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        }<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">func<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">a<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;a&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">b<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;b&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">c<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;c&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">d<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;d&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;e&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ Unreachable.<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ Never created, never disposed.<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">f<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;f&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #795E26;\">func<\/span><span style=\"color: #000000;\">();<\/span>\r\n<span style=\"color: #008000;\">\/\/ Creating a<\/span>\r\n<span style=\"color: #008000;\">\/\/ Creating b<\/span>\r\n<span style=\"color: #008000;\">\/\/ Creating c<\/span>\r\n<span style=\"color: #008000;\">\/\/ Creating d<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing d<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing c<\/span>\r\n<span style=\"color: #008000;\">\/\/ Creating e<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing e<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing b<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing a<\/span>\r\n<\/code><\/pre>\n<p><code>using<\/code> declarations are supposed to be resilient to exceptions;\nif an error is thrown, it&#8217;s rethrown after disposal.\nOn the other hand, the body of your function might execute as expected, but the <code>Symbol.dispose<\/code> might throw.\nIn that case, that exception is rethrown as well.<\/p>\n<p>But what happens if both the logic before and during disposal throws an error?\nFor those cases, <code>SuppressedError<\/code> has been introduced as a new subtype of <code>Error<\/code>.\nIt features a <code>suppressed<\/code> property that holds the last-thrown error, and an <code>error<\/code> property for the most-recently thrown error.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">class<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">ErrorA<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">extends<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Error<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #A31515;\">&quot;ErrorA&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<span style=\"color: #0000FF;\">class<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">ErrorB<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">extends<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Error<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #A31515;\">&quot;ErrorB&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">throwy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">id<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        [<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">dispose<\/span><span style=\"color: #000000;\">]() {<\/span>\r\n<span style=\"color: #000000;\">            <\/span><span style=\"color: #AF00DB;\">throw<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">ErrorA<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">`Error from <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">id<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        }<\/span>\r\n<span style=\"color: #000000;\">    };<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">func<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">a<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">throwy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;a&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">throw<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">ErrorB<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;oops!&quot;<\/span><span style=\"color: #000000;\">)<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #AF00DB;\">try<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #795E26;\">func<\/span><span style=\"color: #000000;\">();<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<span style=\"color: #AF00DB;\">catch<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">any<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\">); <\/span><span style=\"color: #008000;\">\/\/ SuppressedError<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">message<\/span><span style=\"color: #000000;\">); <\/span><span style=\"color: #008000;\">\/\/ An error was suppressed during disposal.<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">error<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\">); <\/span><span style=\"color: #008000;\">\/\/ ErrorA<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">error<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">message<\/span><span style=\"color: #000000;\">); <\/span><span style=\"color: #008000;\">\/\/ Error from a<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">suppressed<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\">); <\/span><span style=\"color: #008000;\">\/\/ ErrorB<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">suppressed<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">message<\/span><span style=\"color: #000000;\">); <\/span><span style=\"color: #008000;\">\/\/ oops!<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>You might have noticed that we&#8217;re using synchronous methods in these examples.\nHowever, lots of resource disposal involves <em>asynchronous<\/em> operations, and we need to wait for those to complete before we continue running any other code.<\/p>\n<p>That&#8217;s why there is also a new <code>Symbol.asyncDispose<\/code>, and it brings us to the next star of the show \u2014 <code>await using<\/code> declarations.\nThese are similar to <code>using<\/code> declarations, but the key is that they look up whose disposal must be <code>await<\/code>ed.\nThey use a different method named by <code>Symbol.asyncDispose<\/code>, though they can operate on anything with a <code>Symbol.dispose<\/code> as well.\nFor convenience, TypeScript also introduces a global type called <code>AsyncDisposable<\/code> that describes any object with an asynchronous dispose method.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">async<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doWork<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ Do fake work for half a second.<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">await<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Promise<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">resolve<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">=&gt;<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">setTimeout<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">resolve<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #098658;\">500<\/span><span style=\"color: #000000;\">));<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">id<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">): <\/span><span style=\"color: #267F99;\">AsyncDisposable<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">`Constructing <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">id<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">async<\/span><span style=\"color: #000000;\"> [<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">asyncDispose<\/span><span style=\"color: #000000;\">]() {<\/span>\r\n<span style=\"color: #000000;\">            <\/span><span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">`Disposing (async) <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">id<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">            <\/span><span style=\"color: #AF00DB;\">await<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doWork<\/span><span style=\"color: #000000;\">();<\/span>\r\n<span style=\"color: #000000;\">        },<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">async<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">func<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">await<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">a<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;a&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">await<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">b<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;b&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">await<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">c<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;c&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">await<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">d<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;d&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">await<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">e<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;e&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ Unreachable.<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ Never created, never disposed.<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">await<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">f<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">loggy<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;f&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #795E26;\">func<\/span><span style=\"color: #000000;\">();<\/span>\r\n<span style=\"color: #008000;\">\/\/ Constructing a<\/span>\r\n<span style=\"color: #008000;\">\/\/ Constructing b<\/span>\r\n<span style=\"color: #008000;\">\/\/ Constructing c<\/span>\r\n<span style=\"color: #008000;\">\/\/ Constructing d<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing (async) d<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing (async) c<\/span>\r\n<span style=\"color: #008000;\">\/\/ Constructing e<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing (async) e<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing (async) b<\/span>\r\n<span style=\"color: #008000;\">\/\/ Disposing (async) a<\/span>\r\n<\/code><\/pre>\n<p>Defining types in terms of <code>Disposable<\/code> and <code>AsyncDisposable<\/code> can make your code much easier to work with if you expect others to do tear-down logic consistently.\nIn fact, lots of existing types exist in the wild which have a <code>dispose()<\/code> or <code>close()<\/code> method.\nFor example, the Visual Studio Code APIs even define <a href=\"https:\/\/code.visualstudio.com\/api\/references\/vscode-api#Disposable\">their own <code>Disposable<\/code> interface<\/a>.\nAPIs in the browser and in runtimes like Node.js, Deno, and Bun might also choose to use <code>Symbol.dispose<\/code> and <code>Symbol.asyncDispose<\/code> for objects which already have clean-up methods, like file handles, connections, and more.<\/p>\n<p>Now maybe this all sounds great for libraries, but a little bit heavy-weight for your scenarios.\nIf you&#8217;re doing a lot of ad-hoc clean-up, creating a new type might introduce a lot of over-abstraction and questions about best-practices.\nFor example, take our <code>TempFile<\/code> example again.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">class<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">TempFile<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">implements<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Disposable<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">#path<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">#handle<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">number<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">constructor<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">#path<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">#handle<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">openSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;w+&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ other methods<\/span>\r\n\r\n<span style=\"color: #000000;\">    [<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">dispose<\/span><span style=\"color: #000000;\">]() {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ Close the file and delete it.<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">closeSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">#handle<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">unlinkSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">#path<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doSomeWork<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">file<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">TempFile<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;.some_temp_file&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ use file...<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #795E26;\">someCondition<\/span><span style=\"color: #000000;\">()) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ do some more work...<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>All we wanted was to remember to call two functions \u2014 but was this the best way to write it?\nShould we be calling <code>openSync<\/code> in the constructor, create an <code>open()<\/code> method, or pass in the handle ourselves?\nShould we expose a method for every possible operation we need to perform, or should we just make the properties public?<\/p>\n<p>That brings us to the final stars of the feature: <code>DisposableStack<\/code> and <code>AsyncDisposableStack<\/code>.\nThese objects are useful for doing both one-off clean-up, along with arbitrary amounts of cleanup.\nA <code>DisposableStack<\/code> is an object that has several methods for keeping track of <code>Disposable<\/code> objects, and can be given functions for doing arbitrary clean-up work.\nWe can also assign them to <code>using<\/code> variables because \u2014 get this \u2014 <em>they&#8217;re also <code>Disposable<\/code><\/em>!\nSo here&#8217;s how we could&#8217;ve written the original example.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">doSomeWork<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">path<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #A31515;\">&quot;.some_temp_file&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">file<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">openSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;w+&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">using<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">cleanup<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">DisposableStack<\/span><span style=\"color: #000000;\">();<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">cleanup<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">defer<\/span><span style=\"color: #000000;\">(() <\/span><span style=\"color: #0000FF;\">=&gt;<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">closeSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">file<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">fs<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">unlinkSync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">path<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    });<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ use file...<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #795E26;\">someCondition<\/span><span style=\"color: #000000;\">()) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ do some more work...<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ ...<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>Here, the <code>defer()<\/code> method just takes a callback, and that callback will be run once <code>cleanup<\/code> is disposed of.\nTypically, <code>defer<\/code> (and other <code>DisposableStack<\/code> methods like <code>use<\/code> and <code>adopt<\/code>)\nshould be called immediately after creating a resource.\nAs the name suggests, <code>DisposableStack<\/code> disposes of everything it keeps track of like a stack, in a first-in-last-out order, so <code>defer<\/code>ing immediately after creating a value helps avoid odd dependency issues.\n<code>AsyncDisposableStack<\/code> works similarly, but can keep track of <code>async<\/code> functions and <code>AsyncDisposable<\/code>s, and is itself an <code>AsyncDisposable.<\/code><\/p>\n<p>The <code>defer<\/code> method is similar in many ways to the <code>defer<\/code> keyword in <a href=\"https:\/\/go.dev\/tour\/flowcontrol\/12\">Go<\/a>, <a href=\"https:\/\/docs.swift.org\/swift-book\/documentation\/the-swift-programming-language\/statements\/#Defer-Statement\">Swift<\/a>, <a href=\"https:\/\/ziglang.org\/documentation\/master\/#defer\">Zig<\/a>, <a href=\"https:\/\/odin-lang.org\/docs\/overview\/#defer-statement\">Odin<\/a>, and others, where the conventions should be similar.<\/p>\n<p>Because this feature is so recent, most runtimes will not support it natively.\nTo use it, you will need runtime polyfills for the following:<\/p>\n<ul>\n<li><code>Symbol.dispose<\/code><\/li>\n<li><code>Symbol.asyncDispose<\/code><\/li>\n<li><code>DisposableStack<\/code><\/li>\n<li><code>AsyncDisposableStack<\/code><\/li>\n<li><code>SuppressedError<\/code><\/li>\n<\/ul>\n<p>However, if all you&#8217;re interested in is <code>using<\/code> and <code>await using<\/code>, you should be able to get away with only polyfilling the built-in <code>symbol<\/code>s.\nSomething as simple as the following should work for most cases:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">dispose<\/span><span style=\"color: #000000;\"> ??= <\/span><span style=\"color: #795E26;\">Symbol<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;Symbol.dispose&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">asyncDispose<\/span><span style=\"color: #000000;\"> ??= <\/span><span style=\"color: #795E26;\">Symbol<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;Symbol.asyncDispose&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<\/code><\/pre>\n<p>You will also need to set your compilation <code>target<\/code> to <code>es2022<\/code> or below, and configure your <code>lib<\/code> setting to either include <code>&quot;esnext&quot;<\/code> or <code>&quot;esnext.disposable&quot;<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #000000;\">{<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0451A5;\">&quot;compilerOptions&quot;<\/span><span style=\"color: #000000;\">: {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0451A5;\">&quot;target&quot;<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #A31515;\">&quot;es2022&quot;<\/span><span style=\"color: #000000;\">,<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0451A5;\">&quot;lib&quot;<\/span><span style=\"color: #000000;\">: [<\/span><span style=\"color: #A31515;\">&quot;es2022&quot;<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;esnext.disposable&quot;<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;dom&quot;<\/span><span style=\"color: #000000;\">]<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>For more information on this feature, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/54505\">take a look at the work on GitHub<\/a>!<\/p>\n<h2>Decorator Metadata<\/h2>\n<p>TypeScript 5.2 implements <a href=\"https:\/\/github.com\/tc39\/proposal-decorator-metadata\">an upcoming ECMAScript feature called decorator metadata<\/a>.<\/p>\n<p>The key idea of this feature is to make it easy for decorators to create and consume metadata on any class they&#8217;re used on or within.<\/p>\n<p>Whenever decorator functions are used, they now have access to a new <code>metadata<\/code> property on their context object.\nThe <code>metadata<\/code> property just holds a simple object.\nSince JavaScript lets us add properties arbitrarily, it can be used as a dictionary that is updated by each decorator.\nAlternatively, since every <code>metadata<\/code> object will be identical for each decorated portion of a class, it can be used as a key into a <code>Map<\/code>.\nAfter all decorators on or in a class get run, that object can be accessed on the class via <code>Symbol.metadata<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">interface<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Context<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">Record<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">PropertyKey<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #267F99;\">unknown<\/span><span style=\"color: #000000;\">&gt;;<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">setMetadata<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">_target<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">any<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">Context<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">[<\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\">] = <\/span><span style=\"color: #0000FF;\">true<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">class<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">SomeClass<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    @<\/span><span style=\"color: #001080;\">setMetadata<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">foo<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #098658;\">123<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #000000;\">    @<\/span><span style=\"color: #001080;\">setMetadata<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">accessor<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">bar<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #A31515;\">&quot;hello!&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #000000;\">    @<\/span><span style=\"color: #001080;\">setMetadata<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #795E26;\">baz<\/span><span style=\"color: #000000;\">() { }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">ourMetadata<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">SomeClass<\/span><span style=\"color: #000000;\">[<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">];<\/span>\r\n\r\n<span style=\"color: #001080;\">console<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">log<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #0070C1;\">JSON<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">stringify<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">ourMetadata<\/span><span style=\"color: #000000;\">));<\/span>\r\n<span style=\"color: #008000;\">\/\/ { &quot;bar&quot;: true, &quot;baz&quot;: true, &quot;foo&quot;: true }<\/span>\r\n<\/code><\/pre>\n<p>This can be useful in a number of different scenarios.\nMetadata could possibly be attached for lots of uses like debugging, serialization, or performing dependency injection with decorators.\nSince metadata objects are created per decorated class, frameworks can either privately use them as keys into a <code>Map<\/code> or <code>WeakMap<\/code>, or tack properties on as necessary.<\/p>\n<p>For example, let&#8217;s say we wanted to use decorators to keep track of which properties and accessors are serializable when using <code>JSON.stringify<\/code> like so:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #AF00DB;\">import<\/span><span style=\"color: #000000;\"> { <\/span><span style=\"color: #001080;\">serialize<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #001080;\">jsonify<\/span><span style=\"color: #000000;\"> } <\/span><span style=\"color: #AF00DB;\">from<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">&quot;.\/serializer&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #0000FF;\">class<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Person<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">firstName<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">lastName<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #000000;\">    @<\/span><span style=\"color: #001080;\">serialize<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">age<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">number<\/span>\r\n\r\n<span style=\"color: #000000;\">    @<\/span><span style=\"color: #001080;\">serialize<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">get<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">fullName<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000FF;\">.<\/span><span style=\"color: #001080;\">firstName<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\"> <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000FF;\">.<\/span><span style=\"color: #001080;\">lastName<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #795E26;\">toJSON<\/span><span style=\"color: #000000;\">() {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">jsonify<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #0000FF;\">this<\/span><span style=\"color: #000000;\">)<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">constructor<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">firstName<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #001080;\">lastName<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #001080;\">age<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">number<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #008000;\">\/\/ ...<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>Here, the intent is that only <code>age<\/code> and <code>fullName<\/code> should be serialized because they are marked with the <code>@serialize<\/code> decorator.\nWe define a <code>toJSON<\/code> method for this purpose, but it just calls out to <code>jsonify<\/code> which uses the metadata that <code>@serialize<\/code> created.<\/p>\n<p>Here&#8217;s an example of how the module <code>.\/serialize.ts<\/code> might be defined:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">serializables<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #795E26;\">Symbol<\/span><span style=\"color: #000000;\">();<\/span>\r\n\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Context<\/span><span style=\"color: #000000;\"> =<\/span>\r\n<span style=\"color: #000000;\">    | <\/span><span style=\"color: #267F99;\">ClassAccessorDecoratorContext<\/span>\r\n<span style=\"color: #000000;\">    | <\/span><span style=\"color: #267F99;\">ClassGetterDecoratorContext<\/span>\r\n<span style=\"color: #000000;\">    | <\/span><span style=\"color: #267F99;\">ClassFieldDecoratorContext<\/span>\r\n<span style=\"color: #000000;\">    ;<\/span>\r\n\r\n<span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">serialize<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">_target<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">any<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">Context<\/span><span style=\"color: #000000;\">): <\/span><span style=\"color: #267F99;\">void<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">static<\/span><span style=\"color: #000000;\"> || <\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">private<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">throw<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">Error<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;Can only serialize public instance members.&quot;<\/span><span style=\"color: #000000;\">)<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #0000FF;\">typeof<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\"> === <\/span><span style=\"color: #A31515;\">&quot;symbol&quot;<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">throw<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">Error<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;Cannot serialize symbol-named properties.&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">propNames<\/span><span style=\"color: #000000;\"> =<\/span>\r\n<span style=\"color: #000000;\">        (<\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">[<\/span><span style=\"color: #001080;\">serializables<\/span><span style=\"color: #000000;\">] <\/span><span style=\"color: #AF00DB;\">as<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">[] | <\/span><span style=\"color: #267F99;\">undefined<\/span><span style=\"color: #000000;\">) ??= [];<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">push<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">jsonify<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">instance<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">object<\/span><span style=\"color: #000000;\">): <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">metadata<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">instance<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">constructor<\/span><span style=\"color: #000000;\">[<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">];<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">propNames<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">?.[<\/span><span style=\"color: #001080;\">serializables<\/span><span style=\"color: #000000;\">] <\/span><span style=\"color: #AF00DB;\">as<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">[] | <\/span><span style=\"color: #267F99;\">undefined<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (!<\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">throw<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">Error<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;No members marked with @serialize.&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">pairStrings<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">map<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">key<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">=&gt;<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">strKey<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0070C1;\">JSON<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">stringify<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">key<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">strValue<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0070C1;\">JSON<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">stringify<\/span><span style=\"color: #000000;\">((<\/span><span style=\"color: #001080;\">instance<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #AF00DB;\">as<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">any<\/span><span style=\"color: #000000;\">)[<\/span><span style=\"color: #001080;\">key<\/span><span style=\"color: #000000;\">]);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">strKey<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">: <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">strValue<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    });<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">`{ <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">pairStrings<\/span><span style=\"color: #000000FF;\">.<\/span><span style=\"color: #795E26;\">join<\/span><span style=\"color: #000000FF;\">(<\/span><span style=\"color: #A31515;\">&quot;, &quot;<\/span><span style=\"color: #000000FF;\">)<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\"> }`<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>This module has a local <code>symbol<\/code> called <code>serializables<\/code> to store and retrieve the names of properties marked <code>@serializable<\/code>.\nIt stores a list of these property names on the metadata on each invocation of <code>@serializable<\/code>.\nWhen <code>jsonify<\/code> is called, the list of properties is fetched off of the metadata and used to retrieve the actual values from the instance, eventually serializing those names and values.<\/p>\n<p>Using a <code>symbol<\/code> technically makes this data accessible to others.\nAn alternative might be to use a <code>WeakMap<\/code> using the metadata object as a key.\nThis keeps data private and happens to use fewer type assertions in this case, but is otherwise similar.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">serializables<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">WeakMap<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">object<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">[]&gt;();<\/span>\r\n\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Context<\/span><span style=\"color: #000000;\"> =<\/span>\r\n<span style=\"color: #000000;\">    | <\/span><span style=\"color: #267F99;\">ClassAccessorDecoratorContext<\/span>\r\n<span style=\"color: #000000;\">    | <\/span><span style=\"color: #267F99;\">ClassGetterDecoratorContext<\/span>\r\n<span style=\"color: #000000;\">    | <\/span><span style=\"color: #267F99;\">ClassFieldDecoratorContext<\/span>\r\n<span style=\"color: #000000;\">    ;<\/span>\r\n\r\n<span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">serialize<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">_target<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">any<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">Context<\/span><span style=\"color: #000000;\">): <\/span><span style=\"color: #267F99;\">void<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">static<\/span><span style=\"color: #000000;\"> || <\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">private<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">throw<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">Error<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;Can only serialize public instance members.&quot;<\/span><span style=\"color: #000000;\">)<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #0000FF;\">typeof<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\"> !== <\/span><span style=\"color: #A31515;\">&quot;string&quot;<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">throw<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">Error<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;Can only serialize string properties.&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">let<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">serializables<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">get<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (<\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\"> === <\/span><span style=\"color: #0000FF;\">undefined<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #001080;\">serializables<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">set<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\"> = []);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">push<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">context<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">name<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">jsonify<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">instance<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">object<\/span><span style=\"color: #000000;\">): <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">metadata<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">instance<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">constructor<\/span><span style=\"color: #000000;\">[<\/span><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">];<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">propNames<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\"> &amp;&amp; <\/span><span style=\"color: #001080;\">serializables<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">get<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">if<\/span><span style=\"color: #000000;\"> (!<\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">throw<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">new<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">Error<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;No members marked with @serialize.&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">pairStrings<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #001080;\">propNames<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">map<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">key<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">=&gt;<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">strKey<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0070C1;\">JSON<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">stringify<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">key<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0000FF;\">const<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0070C1;\">strValue<\/span><span style=\"color: #000000;\"> = <\/span><span style=\"color: #0070C1;\">JSON<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">stringify<\/span><span style=\"color: #000000;\">((<\/span><span style=\"color: #001080;\">instance<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #AF00DB;\">as<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">any<\/span><span style=\"color: #000000;\">)[<\/span><span style=\"color: #001080;\">key<\/span><span style=\"color: #000000;\">]);<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">strKey<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">: <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">strValue<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\">`<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    });<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">return<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">`{ <\/span><span style=\"color: #0000FF;\">${<\/span><span style=\"color: #001080;\">pairStrings<\/span><span style=\"color: #000000FF;\">.<\/span><span style=\"color: #795E26;\">join<\/span><span style=\"color: #000000FF;\">(<\/span><span style=\"color: #A31515;\">&quot;, &quot;<\/span><span style=\"color: #000000FF;\">)<\/span><span style=\"color: #0000FF;\">}<\/span><span style=\"color: #A31515;\"> }`<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>As a note, these implementations don&#8217;t handle subclassing and inheritance.\nThat&#8217;s left as an exercise to you (and you might find that it is easier in one version of the file than the other!).<\/p>\n<p>Because this feature is still fresh, most runtimes will not support it natively.\nTo use it, you will need a polyfill for <code>Symbol.metadata<\/code>.\nSomething as simple as the following should work for most cases:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #001080;\">Symbol<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #001080;\">metadata<\/span><span style=\"color: #000000;\"> ??= <\/span><span style=\"color: #795E26;\">Symbol<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #A31515;\">&quot;Symbol.metadata&quot;<\/span><span style=\"color: #000000;\">);<\/span>\r\n<\/code><\/pre>\n<p>You will also need to set your compilation <code>target<\/code> to <code>es2022<\/code> or below, and configure your <code>lib<\/code> setting to either include <code>&quot;esnext&quot;<\/code> or <code>&quot;esnext.decorators&quot;<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #000000;\">{<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0451A5;\">&quot;compilerOptions&quot;<\/span><span style=\"color: #000000;\">: {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0451A5;\">&quot;target&quot;<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #A31515;\">&quot;es2022&quot;<\/span><span style=\"color: #000000;\">,<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #0451A5;\">&quot;lib&quot;<\/span><span style=\"color: #000000;\">: [<\/span><span style=\"color: #A31515;\">&quot;es2022&quot;<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;esnext.decorators&quot;<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #A31515;\">&quot;dom&quot;<\/span><span style=\"color: #000000;\">]<\/span>\r\n<span style=\"color: #000000;\">    }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>We&#8217;d like to thank <a href=\"https:\/\/github.com\/a-tarasyuk\">Oleksandr Tarasiuk<\/a> for contributing <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/54657\">the implementation of decorator metadata<\/a> for TypeScript 5.2!<\/p>\n<p><!-- TODO: Why is there a conditional type around the existence of `Symbol.metadata`? --><\/p>\n<h2>Named and Anonymous Tuple Elements<\/h2>\n<p>Tuple types have supported optional labels or names for each element.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Pair<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">&gt; = [first: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">, second: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">];<\/span>\r\n<\/code><\/pre>\n<p>These labels don&#8217;t change what you&#8217;re allowed to do with them \u2014 they&#8217;re solely to help with readability and tooling.<\/p>\n<p>However, TypeScript previously had a rule that tuples could not mix and match between labeled and unlabeled elements.\nIn other words, either no element could have a label in a tuple, or all elements needed one.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #008000;\">\/\/ \u2705 fine - no labels<\/span>\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Pair1<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">&gt; = [<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">];<\/span>\r\n\r\n<span style=\"color: #008000;\">\/\/ \u2705 fine - all fully labeled<\/span>\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Pair2<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">&gt; = [first: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">, second: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">];<\/span>\r\n\r\n<span style=\"color: #008000;\">\/\/ \u274c previously an error<\/span>\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Pair3<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">&gt; = [first: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">];<\/span>\r\n<span style=\"color: #008000;\">\/\/                         ~<\/span>\r\n<span style=\"color: #008000;\">\/\/ Tuple members must all have names<\/span>\r\n<span style=\"color: #008000;\">\/\/ or all not have names.<\/span>\r\n<\/code><\/pre>\n<p>This could be annoying for rest elements where we&#8217;d be forced to just add a label like <code>rest<\/code> or <code>tail<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #008000;\">\/\/ \u274c previously an error<\/span>\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">TwoOrMore_A<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">&gt; = [first: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">, second: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">, ...<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">[]];<\/span>\r\n<span style=\"color: #008000;\">\/\/                                          ~~~~~~<\/span>\r\n<span style=\"color: #008000;\">\/\/ Tuple members must all have names<\/span>\r\n<span style=\"color: #008000;\">\/\/ or all not have names.<\/span>\r\n\r\n<span style=\"color: #008000;\">\/\/ \u2705<\/span>\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">TwoOrMore_B<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">&gt; = [first: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">, second: <\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">, rest: ...<\/span><span style=\"color: #267F99;\">T<\/span><span style=\"color: #000000;\">[]];<\/span>\r\n<\/code><\/pre>\n<p>It also meant that this restriction had to be enforced internally in the type system, meaning TypeScript would lose labels.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">HasLabels<\/span><span style=\"color: #000000;\"> = [a: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">, b: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">];<\/span>\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">HasNoLabels<\/span><span style=\"color: #000000;\"> = [<\/span><span style=\"color: #267F99;\">number<\/span><span style=\"color: #000000;\">, <\/span><span style=\"color: #267F99;\">number<\/span><span style=\"color: #000000;\">];<\/span>\r\n<span style=\"color: #0000FF;\">type<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">Merged<\/span><span style=\"color: #000000;\"> = [...<\/span><span style=\"color: #267F99;\">HasNoLabels<\/span><span style=\"color: #000000;\">, ...<\/span><span style=\"color: #267F99;\">HasLabels<\/span><span style=\"color: #000000;\">];<\/span>\r\n<span style=\"color: #008000;\">\/\/   ^ [number, number, string, string]<\/span>\r\n<span style=\"color: #008000;\">\/\/<\/span>\r\n<span style=\"color: #008000;\">\/\/     'a' and 'b' were lost in 'Merged'<\/span>\r\n<\/code><\/pre>\n<p>In TypeScript 5.2, the all-or-nothing restriction on tuple labels has been lifted.\nThe language can now also preserve labels when spreading into an unlabeled tuple.<\/p>\n<p>We&#8217;d like to extend our thanks to <a href=\"https:\/\/github.com\/JoshuaKGoldberg\">Josh Goldberg<\/a> and <a href=\"https:\/\/github.com\/Andarist\">Mateusz Burzy\u0144ski<\/a> who <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/53356\">collaborated to lift this restriction<\/a>.<\/p>\n<h2>Easier Method Usage for Unions of Arrays<\/h2>\n<p>In previous versions on TypeScript, calling a method on a union of arrays could end in pain.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">declare<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">let<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #001080;\">array<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">[] | <\/span><span style=\"color: #267F99;\">number<\/span><span style=\"color: #000000;\">[];<\/span>\r\n\r\n<span style=\"color: #001080;\">array<\/span><span style=\"color: #000000;\">.<\/span><span style=\"color: #795E26;\">filter<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">x<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">=&gt;<\/span><span style=\"color: #000000;\"> !!<\/span><span style=\"color: #001080;\">x<\/span><span style=\"color: #000000;\">);<\/span>\r\n<span style=\"color: #008000;\">\/\/    ~~~~~~ error!<\/span>\r\n<span style=\"color: #008000;\">\/\/ This expression is not callable.<\/span>\r\n<span style=\"color: #008000;\">\/\/   Each member of the union type '...' has signatures,<\/span>\r\n<span style=\"color: #008000;\">\/\/   but none of those signatures are compatible<\/span>\r\n<span style=\"color: #008000;\">\/\/   with each other.<\/span>\r\n<\/code><\/pre>\n<p>In this example, TypeScript would try to see if each version of <code>filter<\/code> is compatible across <code>string[]<\/code> and <code>number[]<\/code>.\nWithout a coherent strategy, TypeScript threw its hands in the air and said &quot;I can&#8217;t make it work&quot;.<\/p>\n<p>In TypeScript 5.2, before giving up in these cases, unions of arrays are treated as a special case.\nA new array type is constructed out of each member&#8217;s element type, and then the method is invoked on that.<\/p>\n<p>Taking the above example, <code>string[] | number[]<\/code> is transformed into <code>(string | number)[]<\/code> (or <code>Array&lt;string | number&gt;<\/code>), and <code>filter<\/code> is invoked on that type.\nThere is a slight caveat which is that <code>filter<\/code> will produce an <code>Array&lt;string | number&gt;<\/code> instead of a <code>string[] | number[]<\/code>;\nbut for a freshly produced value there is less risk of something &quot;going wrong&quot;.<\/p>\n<p>This means lots of methods like <code>filter<\/code>, <code>find<\/code>, <code>some<\/code>, <code>every<\/code>, and <code>reduce<\/code> should all be invokable on unions of arrays in cases where they were not previously.<\/p>\n<p>You can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/53489\">read up more details on the implementing pull request<\/a>.<\/p>\n<h2>Type-Only Import Paths with TypeScript Implementation File Extensions<\/h2>\n<p>TypeScript now allows both declaration <em>and<\/em> implementation file extensions to be included in type-only import paths, regardless of whether <code>allowImportingTsExtensions<\/code> is enabled.<\/p>\n<p>This means that you can now write <code>import type<\/code> statements that use <code>.ts<\/code>, <code>.mts<\/code>, <code>.cts<\/code>, and <code>.tsx<\/code> file extensions.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #AF00DB;\">import<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #AF00DB;\">type<\/span><span style=\"color: #000000;\"> { <\/span><span style=\"color: #001080;\">JustAType<\/span><span style=\"color: #000000;\"> } <\/span><span style=\"color: #AF00DB;\">from<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">&quot;.\/justTypes.ts&quot;<\/span><span style=\"color: #000000;\">;<\/span>\r\n\r\n<span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">f<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">param<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">JustAType<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ ...<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>It also means that <code>import()<\/code> types, which can be used in both TypeScript and JavaScript with JSDoc, can use those file extensions.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #008000;\">\/**<\/span>\r\n<span style=\"color: #008000;\"> * <\/span><span style=\"color: #0000FF;\">@param<\/span><span style=\"color: #008000;\"> <\/span><span style=\"color: #267F99;\">{import(&quot;.\/justTypes.ts&quot;).JustAType}<\/span><span style=\"color: #008000;\"> <\/span><span style=\"color: #001080;\">param<\/span>\r\n<span style=\"color: #008000;\"> *\/<\/span>\r\n<span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">f<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">param<\/span><span style=\"color: #000000;\">) {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #008000;\">\/\/ ...<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/54746\">see the change here<\/a>.<\/p>\n<h2>Comma Completions for Object Members<\/h2>\n<p>It can be easy to forget to add a comma when adding a new property to an object.\nPreviously, if you forgot a comma and requested auto-completion, TypeScript would confusingly give poor unrelated completion results.<\/p>\n<p>TypeScript 5.2 now gracefully provides object member completions when you&#8217;re missing a comma.\nBut to just skip past hitting you with a syntax error, it will <em>also<\/em> auto-insert the missing comma.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2023\/06\/comma-completions-5-2-beta.gif\" alt=\"Properties in an object literal are completed despite missing a comma after a prior property. When the property name is completed, the missing comma is automatically inserted.\"><\/p>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/52899\">see the implementation here<\/a>.<\/p>\n<h2>Inline Variable Refactoring<\/h2>\n<p>TypeScript 5.2 now has a refactoring to inline the contents of a variable to all usage sites.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2023\/06\/inline-variable-5-2-beta.gif\" alt=\"A variable called 'path' initialized to a string, having both of its usages replaced\">.<\/p>\n<p>Using the &quot;inline variable&quot; refactoring will eliminate the variable and replace all the variable&#8217;s usages with its initializer.\nNote that this may cause that initializer&#8217;s side-effects to run at a different time, and as many times as the variable has been used.<\/p>\n<p>For more details, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/54281\">see the implementing pull request<\/a>.<\/p>\n<p><!-- Inlay Parameter Hints --><\/p>\n<h2>Optimized Checks for Ongoing Type Compatibility<\/h2>\n<p>Because TypeScript is a structural type system, types occasionally need to be compared in a member-wise fashion;\nhowever, recursive types add some issues here.\nFor example:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">interface<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">A<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">value<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">A<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">other<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">string<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n\r\n<span style=\"color: #0000FF;\">interface<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">B<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">value<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">B<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #001080;\">other<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">number<\/span><span style=\"color: #000000;\">;<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>When checking whether the type <code>A<\/code> is compatible with the type <code>B<\/code>, TypeScript will end up checking whether the types of <code>value<\/code> in <code>A<\/code> and <code>B<\/code> are respectively compatible.\nAt this point, the type system needs to stop checking any further and proceed to check other members.\nTo do this, the type system has to track when any two types are already being related.<\/p>\n<p>Previously TypeScript already kept a stack of type pairs, and iterated through that to determine whether those types are being related.\nWhen this stack is shallow that&#8217;s not a problem; but when the stack isn&#8217;t shallow, that, uh, <a href=\"https:\/\/accidentallyquadratic.tumblr.com\/\">is a problem<\/a>.<\/p>\n<p>In TypeScript 5.3, a simple <code>Set<\/code> helps tracks this information.\nThis reduced the time spent on a reported test case that used the <a href=\"https:\/\/github.com\/drizzle-team\/drizzle-orm\">drizzle<\/a> library by over 33%!<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #000;\">Benchmark 1: old<\/span>\r\n<span style=\"color: #000;\">  Time (mean \u00b1 \u03c3):      3.115 s \u00b1  0.067 s    [User: 4.403 s, System: 0.124 s]<\/span>\r\n<span style=\"color: #000;\">  Range (min \u2026 max):    3.018 s \u2026  3.196 s    10 runs<\/span>\r\n<span style=\"color: #000;\"> <\/span>\r\n<span style=\"color: #000;\">Benchmark 2: new<\/span>\r\n<span style=\"color: #000;\">  Time (mean \u00b1 \u03c3):      2.072 s \u00b1  0.050 s    [User: 3.355 s, System: 0.135 s]<\/span>\r\n<span style=\"color: #000;\">  Range (min \u2026 max):    1.985 s \u2026  2.150 s    10 runs<\/span>\r\n<span style=\"color: #000;\"> <\/span>\r\n<span style=\"color: #000;\">Summary<\/span>\r\n<span style=\"color: #000;\">  'new' ran<\/span>\r\n<span style=\"color: #000;\">    1.50 \u00b1 0.05 times faster than 'old'<\/span>\r\n<span style=\"color: #000;\"><\/span><\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/55224\">Read more on the change here<\/a>.<\/p>\n<h2>Breaking Changes and Correctness Fixes<\/h2>\n<p>TypeScript strives not to unnecessarily introduce breaks;\nhowever, occasionally we must make corrections and improvements so that code can be better-analyzed.<\/p>\n<h2><code>lib.d.ts<\/code> Changes<\/h2>\n<p>Types generated for the DOM may have an impact on your codebase.\nFor more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/54725\">see the DOM updates for TypeScript 5.2<\/a>.<\/p>\n<h2><code>labeledElementDeclarations<\/code> May Hold <code>undefined<\/code> Elements<\/h2>\n<p>In order <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/53356\">to support a mixture of labeled and unlabeled elements<\/a>, TypeScript&#8217;s API has changed slightly.\nThe <code>labeledElementDeclarations<\/code> property of <code>TupleType<\/code> may hold <code>undefined<\/code> for at each position where an element is unlabeled.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #000000;\">  interface TupleType {<\/span>\r\n<span style=\"color: #A31515;\">-     labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[];<\/span>\r\n<span style=\"color: #098658;\">+     labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration | undefined)[];<\/span>\r\n<span style=\"color: #000000;\">  }<\/span>\r\n<\/code><\/pre>\n<h2><code>module<\/code> and <code>moduleResolution<\/code> Must Match Under Recent Node.js settings<\/h2>\n<p>The <code>--module<\/code> and <code>--moduleResolution<\/code> options each support a <code>node16<\/code> and <code>nodenext<\/code> setting.\nThese are effectively &quot;modern Node.js&quot; settings that should be used on any recent Node.js project.\nWhat we&#8217;ve found is that when these two options don&#8217;t agree on whether they are using Node.js-related settings, projects are effectively misconfigured.<\/p>\n<p>In TypeScript 5.2, when using <code>node16<\/code> or <code>nodenext<\/code> for either of the <code>--module<\/code> and <code>--moduleResolution<\/code> options, TypeScript now requires the other to have a similar Node.js-related setting.\nIn cases where the settings diverge, you&#8217;ll likely get an error message like either<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #000;\">Option 'moduleResolution' must be set to 'NodeNext' (or left unspecified) when option 'module' is set to 'NodeNext'.<\/span>\r\n<span style=\"color: #000;\"><\/span><\/code><\/pre>\n<p>or<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #000;\">Option 'module' must be set to 'Node16' when option 'moduleResolution' is set to 'Node16'.<\/span>\r\n<span style=\"color: #000;\"><\/span><\/code><\/pre>\n<p>So for example <code>--module esnext --moduleResolution node16<\/code> will be rejected \u2014 but you may be better off just using <code>--module nodenext<\/code> alone, or <code>--module esnext --moduleResolution bundler<\/code>.<\/p>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/54567\">see the change here<\/a>.<\/p>\n<h2>Consistent Export Checking for Merged Symbols<\/h2>\n<p>When two declarations merge, they must agree in whether they are both exported.\nDue to a bug, TypeScript missed specific cases in ambient contexts, like in declaration files or <code>declare module<\/code> blocks.\nFor example, it would not issue an error on a case like the following, where <code>replaceInFile<\/code> is declared once as an exported function, and one as an un-exported namespace.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #0000FF;\">declare<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">module<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #A31515;\">'replace-in-file'<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">replaceInFile<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">config<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">unknown<\/span><span style=\"color: #000000;\">): <\/span><span style=\"color: #267F99;\">Promise<\/span><span style=\"color: #000000;\">&lt;<\/span><span style=\"color: #267F99;\">unknown<\/span><span style=\"color: #000000;\">[]&gt;;<\/span>\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> {};<\/span>\r\n\r\n<span style=\"color: #000000;\">    <\/span><span style=\"color: #0000FF;\">namespace<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #267F99;\">replaceInFile<\/span><span style=\"color: #000000;\"> {<\/span>\r\n<span style=\"color: #000000;\">        <\/span><span style=\"color: #AF00DB;\">export<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #0000FF;\">function<\/span><span style=\"color: #000000;\"> <\/span><span style=\"color: #795E26;\">sync<\/span><span style=\"color: #000000;\">(<\/span><span style=\"color: #001080;\">config<\/span><span style=\"color: #000000;\">: <\/span><span style=\"color: #267F99;\">unknown<\/span><span style=\"color: #000000;\">): <\/span><span style=\"color: #267F99;\">unknown<\/span><span style=\"color: #000000;\">[];<\/span>\r\n<span style=\"color: #000000;\">  }<\/span>\r\n<span style=\"color: #000000;\">}<\/span>\r\n<\/code><\/pre>\n<p>In an ambient module, adding an <code>export { ... }<\/code> or a similar construct like <code>export default ...<\/code> implicitly changes whether all declarations are automatically exported.\nTypeScript now recognizes these unfortunately confusing semantics more consistently, and issues an error on the fact that all declarations of <code>replaceInFile<\/code> need to agree in their modifiers, and will issue the following error:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span style=\"color: #000;\">Individual declarations in merged declaration 'replaceInFile' must be all exported or all local.<\/span>\r\n<span style=\"color: #000;\"><\/span><\/code><\/pre>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/54659\">see the change here<\/a>.<\/p>\n<h2>What&#8217;s Next?<\/h2>\n<p>At this point, we do not expect any major changes to TypeScript 5.2.\nOver the next 2 weeks we&#8217;re seeking feedback, and we only expect to introduce low-risk changes for new behaviors, and address critical issues.\n<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/54298\">You can take a look at the 5.2 iteration plan for more information on target dates and more<\/a>.<\/p>\n<p>So please try out the RC today and let us know what you think!<\/p>\n<p>Happy Hacking!<\/p>\n<p>&#8211; Daniel Rosenwasser and the TypeScript Team<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re excited to announce our Release Candidate of TypeScript 5.2! Between now and the stable release of TypeScript 5.2, we expect no further changes apart from critical bug fixes. To get started using the RC, you can get it through NuGet, or through npm with the following command: npm install -D typescript@rc Here&#8217;s a [&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-4001","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 of TypeScript 5.2! Between now and the stable release of TypeScript 5.2, we expect no further changes apart from critical bug fixes. To get started using the RC, you can get it through NuGet, or through npm with the following command: npm install -D typescript@rc Here&#8217;s a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/4001","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=4001"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/4001\/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=4001"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=4001"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=4001"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}