{"id":3779,"date":"2023-03-16T08:59:57","date_gmt":"2023-03-16T16:59:57","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=3779"},"modified":"2023-03-17T09:20:57","modified_gmt":"2023-03-17T17:20:57","slug":"announcing-typescript-5-0","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-0\/","title":{"rendered":"Announcing TypeScript 5.0"},"content":{"rendered":"<p>Today we&#8217;re excited to announce the release of TypeScript 5.0!<\/p>\n<p>This release brings many new features, while aiming to make TypeScript smaller, simpler, and faster.\nWe&#8217;ve implemented the new decorators standard, added functionality to better support ESM projects in Node and bundlers, provided new ways for library authors to control generic inference, expanded our JSDoc functionality, simplified configuration, and made many other improvements.<\/p>\n<p>If you&#8217;re not familiar with TypeScript yet, it&#8217;s a language that builds on JavaScript by adding syntax for types which can be used for type-checking.\nType-checking can help catch lots of common mistakes, from typos to logic errors.\nBringing types to JavaScript also allows us to build great tooling, since types can power features like code completions, go-to-definition, and refactorings in your favorite editor.\nIn fact, if you&#8217;ve used editors like Visual Studio or VS Code, TypeScript already provides the JavaScript experience there!\nYou can read up about the language at <a href=\"https:\/\/typescriptlang.org\">https:\/\/typescriptlang.org<\/a>.<\/p>\n<p>But if you&#8217;re already familiar with TypeScript, have no fear!\n5.0 is not a disruptive release, and everything you know is still applicable.\nWhile TypeScript 5.0 includes correctness changes and some deprecations for infrequently-used options, we believe most developers will have an upgrade experience similar to previous releases.<\/p>\n<p>To get started using TypeScript 5.0, you can get it <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.TypeScript.MSBuild\">through NuGet<\/a>, or use npm with the following command:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>npm install -D typescript<\/span>\r\n<\/code><\/pre>\n<p>You can also follow directions for using a newer version of TypeScript in <a href=\"https:\/\/code.visualstudio.com\/docs\/typescript\/typescript-compiling#_using-the-workspace-version-of-typescript\">Visual Studio Code<\/a>.<\/p>\n<p>Here&#8217;s a quick list of what&#8217;s new in TypeScript 5.0!<\/p>\n<ul>\n<li><a href=\"#decorators\">Decorators<\/a><\/li>\n<li><a href=\"#const-type-parameters\"><code>const<\/code> Type Parameters<\/a><\/li>\n<li><a href=\"#supporting-multiple-configuration-files-in-extends\">Supporting Multiple Configuration Files in <code>extends<\/code><\/a><\/li>\n<li><a href=\"#all-enums-are-union-enums\">All <code>enum<\/code>s Are Union <code>enum<\/code>s<\/a><\/li>\n<li><a href=\"#moduleresolution-bundler\"><code>--moduleResolution bundler<\/code><\/a><\/li>\n<li><a href=\"#resolution-customization-flags\">Resolution Customization Flags<\/a><\/li>\n<li><a href=\"#verbatimmodulesyntax\"><code>--verbatimModuleSyntax<\/code><\/a><\/li>\n<li><a href=\"#support-for-export-type\">Support for <code>export type *<\/code><\/a><\/li>\n<li><a href=\"#satisfies-support-in-jsdoc\"><code>@satisfies<\/code> Support in JSDoc<\/a><\/li>\n<li><a href=\"#overload-support-in-jsdoc\"><code>@overload<\/code> Support in JSDoc<\/a><\/li>\n<li><a href=\"#passing-emit-specific-flags-under-build\">Passing Emit-Specific Flags Under <code>--build<\/code><\/a><\/li>\n<li><a href=\"#case-insensitive-import-sorting-in-editors\">Case-Insensitive Import Sorting in Editors<\/a><\/li>\n<li><a href=\"#exhaustive-switch-case-completions\">Exhaustive <code>switch<\/code>\/<code>case<\/code> Completions<\/a><\/li>\n<li><a href=\"#speed-memory-and-package-size-optimizations\">Speed, Memory, and Package Size Optimizations<\/a><\/li>\n<li><a href=\"#breaking-changes-and-deprecations\">Breaking Changes and Deprecations<\/a><\/li>\n<li><a href=\"#whats-next\">What&#8217;s Next?<\/a><\/li>\n<\/ul>\n<h2><a name=\"beta-delta\"><\/a> What&#8217;s New Since the Beta and RC?<\/h2>\n<p>TypeScript 5.0 has several notable changes <a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-0-beta\/\">since our beta release<\/a>.<\/p>\n<p>One new difference since TypeScript 5.0 Beta is that TypeScript permits <a href=\"#decorators\">decorators<\/a> to be placed before or after <code>export<\/code> and <code>export default<\/code>.\nThis change reflects discussions and consensus within TC39, the standards body for ECMAScript\/JavaScript.<\/p>\n<p>Another is that <a href=\"#moduleresolution-bundler\">the new <code>bundler<\/code> module resolution option<\/a> can now only be used when the <code>--module<\/code> option is set to <code>esnext<\/code>.\nThis was done to ensure that <code>import<\/code> statements written in input files won&#8217;t be transformed to <code>require<\/code> calls before the bundler resolves them, whether or not the bundler or loader respects TypeScript&#8217;s <code>module<\/code> option.\nWe&#8217;ve also provided some context in these release notes recommending most library authors stick to <code>node16<\/code> or <code>nodenext<\/code>.<\/p>\n<p>While TypeScript 5.0 Beta shipped with this functionality, we did not document our work for supporting <a href=\"#case-insensitive-import-sorting-in-editors\">case-insensitive import sorting in editor scenarios<\/a>.\nThis is in part because the UX for customization is still in discussion, but by default, TypeScript should now work better with the rest of your tooling.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-5-0-rc\/\">Since our RC<\/a>, our most notable change is that TypeScript 5.0 now specifies a minimum Node.js version of <code>12.20<\/code> in our <code>package.json<\/code>.\nWe&#8217;ve also published <a href=\"https:\/\/devblogs.microsoft.com\/typescript\/typescripts-migration-to-modules\/\">a write-up about TypeScript 5.0&#8217;s migration to modules<\/a>, and linked to it.<\/p>\n<p>Since TypeScript 5.0 Beta and RC were announced, the specific numbers for <a href=\"#speed-memory-and-package-size-optimizations\">speed benchmarks and package size deltas<\/a> have also been adjusted, though noise has been a factor across runs.\nThe names of some benchmarks have also been adjusted for clarity, and package size improvements have been moved into a separate chart.<\/p>\n<h2>Decorators<\/h2>\n<p>Decorators are an upcoming ECMAScript feature that allow us to customize classes and their members in a reusable way.<\/p>\n<p>Let&#8217;s consider the following code:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>class<\/span><span> <\/span><span>Person<\/span><span> {<\/span>\r\n<span>    <\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>;<\/span>\r\n<span>    <\/span><span>constructor<\/span><span>(<\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>) {<\/span>\r\n<span>        <\/span><span>this<\/span><span>.<\/span><span>name<\/span><span> = <\/span><span>name<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>greet<\/span><span>() {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`Hello, my name is <\/span><span>${<\/span><span>this<\/span><span>.<\/span><span>name<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n\r\n<span>const<\/span><span> <\/span><span>p<\/span><span> = <\/span><span>new<\/span><span> <\/span><span>Person<\/span><span>(<\/span><span>&quot;Ron&quot;<\/span><span>);<\/span>\r\n<span>p<\/span><span>.<\/span><span>greet<\/span><span>();<\/span>\r\n<\/code><\/pre>\n<p><code>greet<\/code> is pretty simple here, but let&#8217;s imagine it&#8217;s something way more complicated &#8211; maybe it does some async logic, it&#8217;s recursive, it has side effects, etc.\nRegardless of what kind of ball-of-mud you&#8217;re imagining, let&#8217;s say you throw in some <code>console.log<\/code> calls to help debug <code>greet<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>class<\/span><span> <\/span><span>Person<\/span><span> {<\/span>\r\n<span>    <\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>;<\/span>\r\n<span>    <\/span><span>constructor<\/span><span>(<\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>) {<\/span>\r\n<span>        <\/span><span>this<\/span><span>.<\/span><span>name<\/span><span> = <\/span><span>name<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>greet<\/span><span>() {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>&quot;LOG: Entering method.&quot;<\/span><span>);<\/span>\r\n\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`Hello, my name is <\/span><span>${<\/span><span>this<\/span><span>.<\/span><span>name<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>&quot;LOG: Exiting method.&quot;<\/span><span>)<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>This pattern is fairly common.\nIt sure would be nice if there was a way we could do this for every method!<\/p>\n<p>This is where decorators come in.\nWe can write a function called <code>loggedMethod<\/code> that looks like the following:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>loggedMethod<\/span><span>(<\/span><span>originalMethod<\/span><span>: <\/span><span>any<\/span><span>, <\/span><span>_context<\/span><span>: <\/span><span>any<\/span><span>) {<\/span>\r\n\r\n<span>    <\/span><span>function<\/span><span> <\/span><span>replacementMethod<\/span><span>(<\/span><span>this<\/span><span>: <\/span><span>any<\/span><span>, ...<\/span><span>args<\/span><span>: <\/span><span>any<\/span><span>[]) {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>&quot;LOG: Entering method.&quot;<\/span><span>)<\/span>\r\n<span>        <\/span><span>const<\/span><span> <\/span><span>result<\/span><span> = <\/span><span>originalMethod<\/span><span>.<\/span><span>call<\/span><span>(<\/span><span>this<\/span><span>, ...<\/span><span>args<\/span><span>);<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>&quot;LOG: Exiting method.&quot;<\/span><span>)<\/span>\r\n<span>        <\/span><span>return<\/span><span> <\/span><span>result<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>return<\/span><span> <\/span><span>replacementMethod<\/span><span>;<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>&quot;What&#8217;s the deal with all of these <code>any<\/code>s?\nWhat is this, <code>any<\/code>Script!?&quot;<\/p>\n<p>Just be patient &#8211; we&#8217;re keeping things simple for now so that we can focus on what this function is doing.\nNotice that <code>loggedMethod<\/code> takes the original method (<code>originalMethod<\/code>) and returns a function that<\/p>\n<ol>\n<li>logs an &quot;Entering&#8230;&quot; message<\/li>\n<li>passes along <code>this<\/code> and all of its arguments to the original method<\/li>\n<li>logs an &quot;Exiting&#8230;&quot; message, and<\/li>\n<li>returns whatever the original method returned.<\/li>\n<\/ol>\n<p>Now we can use <code>loggedMethod<\/code> to <em>decorate<\/em> the method <code>greet<\/code>:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>class<\/span><span> <\/span><span>Person<\/span><span> {<\/span>\r\n<span>    <\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>;<\/span>\r\n<span>    <\/span><span>constructor<\/span><span>(<\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>) {<\/span>\r\n<span>        <\/span><span>this<\/span><span>.<\/span><span>name<\/span><span> = <\/span><span>name<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    @<\/span><span>loggedMethod<\/span>\r\n<span>    <\/span><span>greet<\/span><span>() {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`Hello, my name is <\/span><span>${<\/span><span>this<\/span><span>.<\/span><span>name<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n\r\n<span>const<\/span><span> <\/span><span>p<\/span><span> = <\/span><span>new<\/span><span> <\/span><span>Person<\/span><span>(<\/span><span>&quot;Ron&quot;<\/span><span>);<\/span>\r\n<span>p<\/span><span>.<\/span><span>greet<\/span><span>();<\/span>\r\n\r\n<span>\/\/ Output:<\/span>\r\n<span>\/\/<\/span>\r\n<span>\/\/   LOG: Entering method.<\/span>\r\n<span>\/\/   Hello, my name is Ron.<\/span>\r\n<span>\/\/   LOG: Exiting method.<\/span>\r\n<\/code><\/pre>\n<p>We just used <code>loggedMethod<\/code> as a decorator above <code>greet<\/code> &#8211; and notice that we wrote it as <code>@loggedMethod<\/code>.\nWhen we did that, it got called with the method <em>target<\/em> and a <em>context object<\/em>.\nBecause <code>loggedMethod<\/code> returned a new function, that function replaced the original definition of <code>greet<\/code>.<\/p>\n<p>We didn&#8217;t mention it yet, but <code>loggedMethod<\/code> was defined with a second parameter.\nIt&#8217;s called a &quot;context object&quot;, and it has some useful information about how the decorated method was declared &#8211; like whether it was a <code>#private<\/code> member, or <code>static<\/code>, or what the name of the method was.\nLet&#8217;s rewrite <code>loggedMethod<\/code> to take advantage of that and print out the name of the method that was decorated.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>loggedMethod<\/span><span>(<\/span><span>originalMethod<\/span><span>: <\/span><span>any<\/span><span>, <\/span><span>context<\/span><span>: <\/span><span>ClassMethodDecoratorContext<\/span><span>) {<\/span>\r\n<span>    <\/span><span>const<\/span><span> <\/span><span>methodName<\/span><span> = <\/span><span>String<\/span><span>(<\/span><span>context<\/span><span>.<\/span><span>name<\/span><span>);<\/span>\r\n\r\n<span>    <\/span><span>function<\/span><span> <\/span><span>replacementMethod<\/span><span>(<\/span><span>this<\/span><span>: <\/span><span>any<\/span><span>, ...<\/span><span>args<\/span><span>: <\/span><span>any<\/span><span>[]) {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`LOG: Entering method '<\/span><span>${<\/span><span>methodName<\/span><span>}<\/span><span>'.`<\/span><span>)<\/span>\r\n<span>        <\/span><span>const<\/span><span> <\/span><span>result<\/span><span> = <\/span><span>originalMethod<\/span><span>.<\/span><span>call<\/span><span>(<\/span><span>this<\/span><span>, ...<\/span><span>args<\/span><span>);<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`LOG: Exiting method '<\/span><span>${<\/span><span>methodName<\/span><span>}<\/span><span>'.`<\/span><span>)<\/span>\r\n<span>        <\/span><span>return<\/span><span> <\/span><span>result<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>return<\/span><span> <\/span><span>replacementMethod<\/span><span>;<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>We&#8217;re now using the context parameter &#8211; and that it&#8217;s the first thing in <code>loggedMethod<\/code> that has a type stricter than <code>any<\/code> and <code>any[]<\/code>.\nTypeScript provides a type called <code>ClassMethodDecoratorContext<\/code> that models the context object that method decorators take.<\/p>\n<p>Apart from metadata, the context object for methods also has a useful function called <code>addInitializer<\/code>.\nIt&#8217;s a way to hook into the beginning of the constructor (or the initialization of the class itself if we&#8217;re working with <code>static<\/code>s).<\/p>\n<p>As an example &#8211; in JavaScript, it&#8217;s common to write something like the following pattern:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>class<\/span><span> <\/span><span>Person<\/span><span> {<\/span>\r\n<span>    <\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>;<\/span>\r\n<span>    <\/span><span>constructor<\/span><span>(<\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>) {<\/span>\r\n<span>        <\/span><span>this<\/span><span>.<\/span><span>name<\/span><span> = <\/span><span>name<\/span><span>;<\/span>\r\n\r\n<span>        <\/span><span>this<\/span><span>.<\/span><span>greet<\/span><span> = <\/span><span>this<\/span><span>.<\/span><span>greet<\/span><span>.<\/span><span>bind<\/span><span>(<\/span><span>this<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>greet<\/span><span>() {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`Hello, my name is <\/span><span>${<\/span><span>this<\/span><span>.<\/span><span>name<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>Alternatively, <code>greet<\/code> might be declared as a property initialized to an arrow function.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>class<\/span><span> <\/span><span>Person<\/span><span> {<\/span>\r\n<span>    <\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>;<\/span>\r\n<span>    <\/span><span>constructor<\/span><span>(<\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>) {<\/span>\r\n<span>        <\/span><span>this<\/span><span>.<\/span><span>name<\/span><span> = <\/span><span>name<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>greet<\/span><span> = () <\/span><span>=&gt;<\/span><span> {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`Hello, my name is <\/span><span>${<\/span><span>this<\/span><span>.<\/span><span>name<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n<span>    };<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>This code is written to ensure that <code>this<\/code> isn&#8217;t re-bound if <code>greet<\/code> is called as a stand-alone function or passed as a callback.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>const<\/span><span> <\/span><span>greet<\/span><span> = <\/span><span>new<\/span><span> <\/span><span>Person<\/span><span>(<\/span><span>&quot;Ron&quot;<\/span><span>).<\/span><span>greet<\/span><span>;<\/span>\r\n\r\n<span>\/\/ We don't want this to fail!<\/span>\r\n<span>greet<\/span><span>();<\/span>\r\n<\/code><\/pre>\n<p>We can write a decorator that uses <code>addInitializer<\/code> to call <code>bind<\/code> in the constructor for us.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>bound<\/span><span>(<\/span><span>originalMethod<\/span><span>: <\/span><span>any<\/span><span>, <\/span><span>context<\/span><span>: <\/span><span>ClassMethodDecoratorContext<\/span><span>) {<\/span>\r\n<span>    <\/span><span>const<\/span><span> <\/span><span>methodName<\/span><span> = <\/span><span>context<\/span><span>.<\/span><span>name<\/span><span>;<\/span>\r\n<span>    <\/span><span>if<\/span><span> (<\/span><span>context<\/span><span>.<\/span><span>private<\/span><span>) {<\/span>\r\n<span>        <\/span><span>throw<\/span><span> <\/span><span>new<\/span><span> <\/span><span>Error<\/span><span>(<\/span><span>`'bound' cannot decorate private properties like <\/span><span>${<\/span><span>methodName<\/span><span> <\/span><span>as<\/span><span> <\/span><span>string<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n<span>    <\/span><span>context<\/span><span>.<\/span><span>addInitializer<\/span><span>(<\/span><span>function<\/span><span> () {<\/span>\r\n<span>        <\/span><span>this<\/span><span>[<\/span><span>methodName<\/span><span>] = <\/span><span>this<\/span><span>[<\/span><span>methodName<\/span><span>].<\/span><span>bind<\/span><span>(<\/span><span>this<\/span><span>);<\/span>\r\n<span>    });<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p><code>bound<\/code> isn&#8217;t returning anything &#8211; so when it decorates a method, it leaves the original alone.\nInstead, it will add logic before any other fields are initialized.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>class<\/span><span> <\/span><span>Person<\/span><span> {<\/span>\r\n<span>    <\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>;<\/span>\r\n<span>    <\/span><span>constructor<\/span><span>(<\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>) {<\/span>\r\n<span>        <\/span><span>this<\/span><span>.<\/span><span>name<\/span><span> = <\/span><span>name<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    @<\/span><span>bound<\/span>\r\n<span>    @<\/span><span>loggedMethod<\/span>\r\n<span>    <\/span><span>greet<\/span><span>() {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`Hello, my name is <\/span><span>${<\/span><span>this<\/span><span>.<\/span><span>name<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n\r\n<span>const<\/span><span> <\/span><span>p<\/span><span> = <\/span><span>new<\/span><span> <\/span><span>Person<\/span><span>(<\/span><span>&quot;Ron&quot;<\/span><span>);<\/span>\r\n<span>const<\/span><span> <\/span><span>greet<\/span><span> = <\/span><span>p<\/span><span>.<\/span><span>greet<\/span><span>;<\/span>\r\n\r\n<span>\/\/ Works!<\/span>\r\n<span>greet<\/span><span>();<\/span>\r\n<\/code><\/pre>\n<p>Notice that we stacked two decorators &#8211; <code>@bound<\/code> and <code>@loggedMethod<\/code>.\nThese decorations run in &quot;reverse order&quot;.\nThat is, <code>@loggedMethod<\/code> decorates the original method <code>greet<\/code>, and <code>@bound<\/code> decorates the result of <code>@loggedMethod<\/code>.\nIn this example, it doesn&#8217;t matter &#8211; but it could if your decorators have side effects or expect a certain order.<\/p>\n<p>Also worth noting: if you&#8217;d prefer stylistically, you can put these decorators on the same line.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>    @<\/span><span>bound<\/span><span> @<\/span><span>loggedMethod<\/span><span> <\/span><span>greet<\/span><span>() {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`Hello, my name is <\/span><span>${<\/span><span>this<\/span><span>.<\/span><span>name<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n<\/code><\/pre>\n<p>Something that might not be obvious is that we can even make functions that <em>return<\/em> decorator functions.\nThat makes it possible to customize the final decorator just a little.\nIf we wanted, we could have made <code>loggedMethod<\/code> return a decorator and customize how it logs its messages.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>loggedMethod<\/span><span>(<\/span><span>headMessage<\/span><span> = <\/span><span>&quot;LOG:&quot;<\/span><span>) {<\/span>\r\n<span>    <\/span><span>return<\/span><span> <\/span><span>function<\/span><span> <\/span><span>actualDecorator<\/span><span>(<\/span><span>originalMethod<\/span><span>: <\/span><span>any<\/span><span>, <\/span><span>context<\/span><span>: <\/span><span>ClassMethodDecoratorContext<\/span><span>) {<\/span>\r\n<span>        <\/span><span>const<\/span><span> <\/span><span>methodName<\/span><span> = <\/span><span>String<\/span><span>(<\/span><span>context<\/span><span>.<\/span><span>name<\/span><span>);<\/span>\r\n\r\n<span>        <\/span><span>function<\/span><span> <\/span><span>replacementMethod<\/span><span>(<\/span><span>this<\/span><span>: <\/span><span>any<\/span><span>, ...<\/span><span>args<\/span><span>: <\/span><span>any<\/span><span>[]) {<\/span>\r\n<span>            <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`<\/span><span>${<\/span><span>headMessage<\/span><span>}<\/span><span> Entering method '<\/span><span>${<\/span><span>methodName<\/span><span>}<\/span><span>'.`<\/span><span>)<\/span>\r\n<span>            <\/span><span>const<\/span><span> <\/span><span>result<\/span><span> = <\/span><span>originalMethod<\/span><span>.<\/span><span>call<\/span><span>(<\/span><span>this<\/span><span>, ...<\/span><span>args<\/span><span>);<\/span>\r\n<span>            <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`<\/span><span>${<\/span><span>headMessage<\/span><span>}<\/span><span> Exiting method '<\/span><span>${<\/span><span>methodName<\/span><span>}<\/span><span>'.`<\/span><span>)<\/span>\r\n<span>            <\/span><span>return<\/span><span> <\/span><span>result<\/span><span>;<\/span>\r\n<span>        }<\/span>\r\n\r\n<span>        <\/span><span>return<\/span><span> <\/span><span>replacementMethod<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>If we did that, we&#8217;d have to call <code>loggedMethod<\/code> before using it as a decorator.\nWe could then pass in any string as the prefix for messages that get logged to the console.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>class<\/span><span> <\/span><span>Person<\/span><span> {<\/span>\r\n<span>    <\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>;<\/span>\r\n<span>    <\/span><span>constructor<\/span><span>(<\/span><span>name<\/span><span>: <\/span><span>string<\/span><span>) {<\/span>\r\n<span>        <\/span><span>this<\/span><span>.<\/span><span>name<\/span><span> = <\/span><span>name<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    @<\/span><span>loggedMethod<\/span><span>(<\/span><span>&quot;\u26a0\ufe0f&quot;<\/span><span>)<\/span>\r\n<span>    <\/span><span>greet<\/span><span>() {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`Hello, my name is <\/span><span>${<\/span><span>this<\/span><span>.<\/span><span>name<\/span><span>}<\/span><span>.`<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n\r\n<span>const<\/span><span> <\/span><span>p<\/span><span> = <\/span><span>new<\/span><span> <\/span><span>Person<\/span><span>(<\/span><span>&quot;Ron&quot;<\/span><span>);<\/span>\r\n<span>p<\/span><span>.<\/span><span>greet<\/span><span>();<\/span>\r\n\r\n<span>\/\/ Output:<\/span>\r\n<span>\/\/<\/span>\r\n<span>\/\/   \u26a0\ufe0f Entering method 'greet'.<\/span>\r\n<span>\/\/   Hello, my name is Ron.<\/span>\r\n<span>\/\/   \u26a0\ufe0f Exiting method 'greet'.<\/span>\r\n<\/code><\/pre>\n<p>Decorators can be used on more than just methods!\nThey can be used on properties\/fields, getters, setters, and auto-accessors.\nEven classes themselves can be decorated for things like subclassing and registration.<\/p>\n<p>To learn more about decorators in-depth, you can read up on <a href=\"https:\/\/2ality.com\/2022\/10\/javascript-decorators.html\">Axel Rauschmayer&#8217;s extensive summary<\/a>.<\/p>\n<p>For more information about the changes involved, you can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50820\">view the original pull request<\/a>.<\/p>\n<h3>Differences with Experimental Legacy Decorators<\/h3>\n<p>If you&#8217;ve been using TypeScript for a while, you might be aware of the fact that it&#8217;s had support for &quot;experimental&quot; decorators for years.\nWhile these experimental decorators have been incredibly useful, they modeled a much older version of the decorators proposal, and always required an opt-in compiler flag called <code>--experimentalDecorators<\/code>.\nAny attempt to use decorators in TypeScript without this flag used to prompt an error message.<\/p>\n<p><code>--experimentalDecorators<\/code> will continue to exist for the foreseeable future;\nhowever, without the flag, decorators will now be valid syntax for all new code.\nOutside of <code>--experimentalDecorators<\/code>, they will be type-checked and emitted differently.\nThe type-checking rules and emit are sufficiently different that while decorators <em>can<\/em> be written to support both the old and new decorators behavior, any existing decorator functions are not likely to do so.<\/p>\n<p>This new decorators proposal is not compatible with <code>--emitDecoratorMetadata<\/code>, and it does not allow decorating parameters.\nFuture ECMAScript proposals may be able to help bridge that gap.<\/p>\n<p>On a final note: in addition to allowing decorators to be placed before the <code>export<\/code> keyword, the proposal for decorators now provides the option of placing decorators after <code>export<\/code> or <code>export default<\/code>.\nThe only exception is that mixing the two styles is not allowed.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ \u2705 allowed<\/span>\r\n<span>@<\/span><span>register<\/span><span> <\/span><span>export<\/span><span> <\/span><span>default<\/span><span> <\/span><span>class<\/span><span> <\/span><span>Foo<\/span><span> {<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ \u2705 also allowed<\/span>\r\n<span>export<\/span><span> <\/span><span>default<\/span><span> @<\/span><span>register<\/span><span> <\/span><span>class<\/span><span> <\/span><span>Bar<\/span><span> {<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ \u274c error - before *and* after is not allowed<\/span>\r\n<span>@<\/span><span>before<\/span><span> <\/span><span>export<\/span><span> @<\/span><span>after<\/span><span> <\/span><span>class<\/span><span> <\/span><span>Bar<\/span><span> {<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<h3>Writing Well-Typed Decorators<\/h3>\n<p>The <code>loggedMethod<\/code> and <code>bound<\/code> decorator examples above are intentionally simple and omit lots of details about types.<\/p>\n<p>Typing decorators can be fairly complex.\nFor example, a well-typed version of <code>loggedMethod<\/code> from above might look something like this:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>loggedMethod<\/span><span>&lt;<\/span><span>This<\/span><span>, <\/span><span>Args<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>any<\/span><span>[], <\/span><span>Return<\/span><span>&gt;(<\/span>\r\n<span>    <\/span><span>target<\/span><span>: (<\/span><span>this<\/span><span>: <\/span><span>This<\/span><span>, ...<\/span><span>args<\/span><span>: <\/span><span>Args<\/span><span>) <\/span><span>=&gt;<\/span><span> <\/span><span>Return<\/span><span>,<\/span>\r\n<span>    <\/span><span>context<\/span><span>: <\/span><span>ClassMethodDecoratorContext<\/span><span>&lt;<\/span><span>This<\/span><span>, (<\/span><span>this<\/span><span>: <\/span><span>This<\/span><span>, ...<\/span><span>args<\/span><span>: <\/span><span>Args<\/span><span>) <\/span><span>=&gt;<\/span><span> <\/span><span>Return<\/span><span>&gt;<\/span>\r\n<span>) {<\/span>\r\n<span>    <\/span><span>const<\/span><span> <\/span><span>methodName<\/span><span> = <\/span><span>String<\/span><span>(<\/span><span>context<\/span><span>.<\/span><span>name<\/span><span>);<\/span>\r\n\r\n<span>    <\/span><span>function<\/span><span> <\/span><span>replacementMethod<\/span><span>(<\/span><span>this<\/span><span>: <\/span><span>This<\/span><span>, ...<\/span><span>args<\/span><span>: <\/span><span>Args<\/span><span>): <\/span><span>Return<\/span><span> {<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`LOG: Entering method '<\/span><span>${<\/span><span>methodName<\/span><span>}<\/span><span>'.`<\/span><span>)<\/span>\r\n<span>        <\/span><span>const<\/span><span> <\/span><span>result<\/span><span> = <\/span><span>target<\/span><span>.<\/span><span>call<\/span><span>(<\/span><span>this<\/span><span>, ...<\/span><span>args<\/span><span>);<\/span>\r\n<span>        <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>`LOG: Exiting method '<\/span><span>${<\/span><span>methodName<\/span><span>}<\/span><span>'.`<\/span><span>)<\/span>\r\n<span>        <\/span><span>return<\/span><span> <\/span><span>result<\/span><span>;<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>return<\/span><span> <\/span><span>replacementMethod<\/span><span>;<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>We had to separately model out the type of <code>this<\/code>, the parameters, and the return type of the original method, using the type parameters <code>This<\/code>, <code>Args<\/code>, and <code>Return<\/code>.<\/p>\n<p>Exactly how complex your decorators functions are defined depends on what you want to guarantee.\nJust keep in mind, your decorators will be used more than they&#8217;re written, so a well-typed version will usually be preferable &#8211; but there&#8217;s clearly a trade-off with readability, so try to keep things simple.<\/p>\n<p>More documentation on writing decorators will be available in the future &#8211; but <a href=\"https:\/\/2ality.com\/2022\/10\/javascript-decorators.html\">this post<\/a> should have a good amount of detail for the mechanics of decorators.<\/p>\n<h2><code>const<\/code> Type Parameters<\/h2>\n<p>When inferring the type of an object, TypeScript will usually choose a type that&#8217;s meant to be general.\nFor example, in this case, the inferred type of <code>names<\/code> is <code>string[]<\/code>:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>type<\/span><span> <\/span><span>HasNames<\/span><span> = { <\/span><span>readonly<\/span><span> <\/span><span>names<\/span><span>: <\/span><span>string<\/span><span>[] };<\/span>\r\n<span>function<\/span><span> <\/span><span>getNamesExactly<\/span><span>&lt;<\/span><span>T<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>HasNames<\/span><span>&gt;(<\/span><span>arg<\/span><span>: <\/span><span>T<\/span><span>): <\/span><span>T<\/span><span>[<\/span><span>&quot;names&quot;<\/span><span>] {<\/span>\r\n<span>    <\/span><span>return<\/span><span> <\/span><span>arg<\/span><span>.<\/span><span>names<\/span><span>;<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ Inferred type: string[]<\/span>\r\n<span>const<\/span><span> <\/span><span>names<\/span><span> = <\/span><span>getNamesExactly<\/span><span>({ <\/span><span>names:<\/span><span> [<\/span><span>&quot;Alice&quot;<\/span><span>, <\/span><span>&quot;Bob&quot;<\/span><span>, <\/span><span>&quot;Eve&quot;<\/span><span>]});<\/span>\r\n<\/code><\/pre>\n<p>Usually the intent of this is to enable mutation down the line.<\/p>\n<p>However, depending on what exactly <code>getNamesExactly<\/code> does and how it&#8217;s intended to be used, it can often be the case that a more-specific type is desired.<\/p>\n<p>Up until now, API authors have typically had to recommend adding <code>as const<\/code> in certain places to achieve the desired inference:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ The type we wanted:<\/span>\r\n<span>\/\/    readonly [&quot;Alice&quot;, &quot;Bob&quot;, &quot;Eve&quot;]<\/span>\r\n<span>\/\/ The type we got:<\/span>\r\n<span>\/\/    string[]<\/span>\r\n<span>const<\/span><span> <\/span><span>names1<\/span><span> = <\/span><span>getNamesExactly<\/span><span>({ <\/span><span>names:<\/span><span> [<\/span><span>&quot;Alice&quot;<\/span><span>, <\/span><span>&quot;Bob&quot;<\/span><span>, <\/span><span>&quot;Eve&quot;<\/span><span>]});<\/span>\r\n\r\n<span>\/\/ Correctly gets what we wanted:<\/span>\r\n<span>\/\/    readonly [&quot;Alice&quot;, &quot;Bob&quot;, &quot;Eve&quot;]<\/span>\r\n<span>const<\/span><span> <\/span><span>names2<\/span><span> = <\/span><span>getNamesExactly<\/span><span>({ <\/span><span>names:<\/span><span> [<\/span><span>&quot;Alice&quot;<\/span><span>, <\/span><span>&quot;Bob&quot;<\/span><span>, <\/span><span>&quot;Eve&quot;<\/span><span>]} <\/span><span>as<\/span><span> <\/span><span>const<\/span><span>);<\/span>\r\n<\/code><\/pre>\n<p>This can be cumbersome and easy to forget.\nIn TypeScript 5.0, you can now add a <code>const<\/code> modifier to a type parameter declaration to cause <code>const<\/code>-like inference to be the default:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>type<\/span><span> <\/span><span>HasNames<\/span><span> = { <\/span><span>names<\/span><span>: <\/span><span>readonly<\/span><span> <\/span><span>string<\/span><span>[] };<\/span>\r\n<span>function<\/span><span> <\/span><span>getNamesExactly<\/span><span>&lt;<\/span><span>const<\/span><span> <\/span><span>T<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>HasNames<\/span><span>&gt;(<\/span><span>arg<\/span><span>: <\/span><span>T<\/span><span>): <\/span><span>T<\/span><span>[<\/span><span>&quot;names&quot;<\/span><span>] {<\/span>\r\n<span>\/\/                       ^^^^^<\/span>\r\n<span>    <\/span><span>return<\/span><span> <\/span><span>arg<\/span><span>.<\/span><span>names<\/span><span>;<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ Inferred type: readonly [&quot;Alice&quot;, &quot;Bob&quot;, &quot;Eve&quot;]<\/span>\r\n<span>\/\/ Note: Didn't need to write 'as const' here<\/span>\r\n<span>const<\/span><span> <\/span><span>names<\/span><span> = <\/span><span>getNamesExactly<\/span><span>({ <\/span><span>names:<\/span><span> [<\/span><span>&quot;Alice&quot;<\/span><span>, <\/span><span>&quot;Bob&quot;<\/span><span>, <\/span><span>&quot;Eve&quot;<\/span><span>] });<\/span>\r\n<\/code><\/pre>\n<p>Note that the <code>const<\/code> modifier doesn&#8217;t <em>reject<\/em> mutable values, and doesn&#8217;t require immutable constraints.\nUsing a mutable type constraint might give surprising results.\nFor example:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>declare<\/span><span> <\/span><span>function<\/span><span> <\/span><span>fnBad<\/span><span>&lt;<\/span><span>const<\/span><span> <\/span><span>T<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>string<\/span><span>[]&gt;(<\/span><span>args<\/span><span>: <\/span><span>T<\/span><span>): <\/span><span>void<\/span><span>;<\/span>\r\n\r\n<span>\/\/ 'T' is still 'string[]' since 'readonly [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]' is not assignable to 'string[]'<\/span>\r\n<span>fnBad<\/span><span>([<\/span><span>&quot;a&quot;<\/span><span>, <\/span><span>&quot;b&quot;<\/span><span> ,<\/span><span>&quot;c&quot;<\/span><span>]);<\/span>\r\n<\/code><\/pre>\n<p>Here, the inferred candidate for <code>T<\/code> is <code>readonly [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]<\/code>, and a <code>readonly<\/code> array can&#8217;t be used where a mutable one is needed.\nIn this case, inference falls back to the constraint, the array is treated as <code>string[]<\/code>, and the call still proceeds successfully.<\/p>\n<p>A better definition of this function should use <code>readonly string[]<\/code>:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>declare<\/span><span> <\/span><span>function<\/span><span> <\/span><span>fnGood<\/span><span>&lt;<\/span><span>const<\/span><span> <\/span><span>T<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>readonly<\/span><span> <\/span><span>string<\/span><span>[]&gt;(<\/span><span>args<\/span><span>: <\/span><span>T<\/span><span>): <\/span><span>void<\/span><span>;<\/span>\r\n\r\n<span>\/\/ T is readonly [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]<\/span>\r\n<span>fnGood<\/span><span>([<\/span><span>&quot;a&quot;<\/span><span>, <\/span><span>&quot;b&quot;<\/span><span> ,<\/span><span>&quot;c&quot;<\/span><span>]);<\/span>\r\n<\/code><\/pre>\n<p>Similarly, remember to keep in mind that the <code>const<\/code> modifier only affects inference of object, array and primitive expressions that were written within the call, so arguments which wouldn&#8217;t (or couldn&#8217;t) be modified with <code>as const<\/code> won&#8217;t see any change in behavior:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>declare<\/span><span> <\/span><span>function<\/span><span> <\/span><span>fnGood<\/span><span>&lt;<\/span><span>const<\/span><span> <\/span><span>T<\/span><span> <\/span><span>extends<\/span><span> <\/span><span>readonly<\/span><span> <\/span><span>string<\/span><span>[]&gt;(<\/span><span>args<\/span><span>: <\/span><span>T<\/span><span>): <\/span><span>void<\/span><span>;<\/span>\r\n<span>const<\/span><span> <\/span><span>arr<\/span><span> = [<\/span><span>&quot;a&quot;<\/span><span>, <\/span><span>&quot;b&quot;<\/span><span> ,<\/span><span>&quot;c&quot;<\/span><span>];<\/span>\r\n\r\n<span>\/\/ 'T' is still 'string[]'-- the 'const' modifier has no effect here<\/span>\r\n<span>fnGood<\/span><span>(<\/span><span>arr<\/span><span>);<\/span>\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51865\">See the pull request<\/a> and the (<a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/30680\">first<\/a> and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/41114\">second<\/a>) motivating issues for more details.<\/p>\n<h2>Supporting Multiple Configuration Files in <code>extends<\/code><\/h2>\n<p>When managing multiple projects, it can be helpful to have a &quot;base&quot; configuration file that other <code>tsconfig.json<\/code> files can extend from.\nThat&#8217;s why TypeScript supports an <code>extends<\/code> field for copying over fields from <code>compilerOptions<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ packages\/front-end\/src\/tsconfig.json<\/span>\r\n<span>{<\/span>\r\n<span>    <\/span><span>&quot;extends&quot;<\/span><span>: <\/span><span>&quot;..\/..\/..\/tsconfig.base.json&quot;<\/span><span>,<\/span>\r\n<span>    <\/span><span>&quot;compilerOptions&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>&quot;outDir&quot;<\/span><span>: <\/span><span>&quot;..\/lib&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>\/\/ ...<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>However, there are scenarios where you might want to extend from multiple configuration files.\nFor example, imagine using <a href=\"https:\/\/github.com\/tsconfig\/bases\">a TypeScript base configuration file shipped to npm<\/a>.\nIf you want all your projects to also use the options from the <code>@tsconfig\/strictest<\/code> package on npm, then there&#8217;s a simple solution: have <code>tsconfig.base.json<\/code> extend from <code>@tsconfig\/strictest<\/code>:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ tsconfig.base.json<\/span>\r\n<span>{<\/span>\r\n<span>    <\/span><span>&quot;extends&quot;<\/span><span>: <\/span><span>&quot;@tsconfig\/strictest\/tsconfig.json&quot;<\/span><span>,<\/span>\r\n<span>    <\/span><span>&quot;compilerOptions&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>\/\/ ...<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>This works to a point.\nIf you have any projects that <em>don&#8217;t<\/em> want to use <code>@tsconfig\/strictest<\/code>, they have to either manually disable the options, or create a separate version of <code>tsconfig.base.json<\/code> that <em>doesn&#8217;t<\/em> extend from <code>@tsconfig\/strictest<\/code>.<\/p>\n<p>To give some more flexibility here, Typescript 5.0 now allows the <code>extends<\/code> field to take multiple entries.\nFor example, in this configuration file:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>{<\/span>\r\n<span>    <\/span><span>&quot;extends&quot;<\/span><span>: [<\/span><span>&quot;a&quot;<\/span><span>, <\/span><span>&quot;b&quot;<\/span><span>, <\/span><span>&quot;c&quot;<\/span><span>],<\/span>\r\n<span>    <\/span><span>&quot;compilerOptions&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>\/\/ ...<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>Writing this is kind of like extending <code>c<\/code> directly, where <code>c<\/code> extends <code>b<\/code>, and <code>b<\/code> extends <code>a<\/code>.\nIf any fields &quot;conflict&quot;, the latter entry wins.<\/p>\n<p>So in the following example, both <code>strictNullChecks<\/code> and <code>noImplicitAny<\/code> are enabled in the final <code>tsconfig.json<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ tsconfig1.json<\/span>\r\n<span>{<\/span>\r\n<span>    <\/span><span>&quot;compilerOptions&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>&quot;strictNullChecks&quot;<\/span><span>: <\/span><span>true<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ tsconfig2.json<\/span>\r\n<span>{<\/span>\r\n<span>    <\/span><span>&quot;compilerOptions&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>&quot;noImplicitAny&quot;<\/span><span>: <\/span><span>true<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ tsconfig.json<\/span>\r\n<span>{<\/span>\r\n<span>    <\/span><span>&quot;extends&quot;<\/span><span>: [<\/span><span>&quot;.\/tsconfig1.json&quot;<\/span><span>, <\/span><span>&quot;.\/tsconfig2.json&quot;<\/span><span>],<\/span>\r\n<span>    <\/span><span>&quot;files&quot;<\/span><span>: [<\/span><span>&quot;.\/index.ts&quot;<\/span><span>]<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>As another example, we can rewrite our original example in the following way.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ packages\/front-end\/src\/tsconfig.json<\/span>\r\n<span>{<\/span>\r\n<span>    <\/span><span>&quot;extends&quot;<\/span><span>: [<\/span><span>&quot;@tsconfig\/strictest\/tsconfig.json&quot;<\/span><span>, <\/span><span>&quot;..\/..\/..\/tsconfig.base.json&quot;<\/span><span>],<\/span>\r\n<span>    <\/span><span>&quot;compilerOptions&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>&quot;outDir&quot;<\/span><span>: <\/span><span>&quot;..\/lib&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>\/\/ ...<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>For more details, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50403\">read more on the original pull request<\/a>.<\/p>\n<h2>All <code>enum<\/code>s Are Union <code>enum<\/code>s<\/h2>\n<p>When TypeScript originally introduced enums, they were nothing more than a set of numeric constants with the same type.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>enum<\/span><span> <\/span><span>E<\/span><span> {<\/span>\r\n<span>    <\/span><span>Foo<\/span><span> = <\/span><span>10<\/span><span>,<\/span>\r\n<span>    <\/span><span>Bar<\/span><span> = <\/span><span>20<\/span><span>,<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>The only thing special about <code>E.Foo<\/code> and <code>E.Bar<\/code> was that they were assignable to anything expecting the type <code>E<\/code>.\nOther than that, they were pretty much just <code>number<\/code>s.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>takeValue<\/span><span>(<\/span><span>e<\/span><span>: <\/span><span>E<\/span><span>) {}<\/span>\r\n\r\n<span>takeValue<\/span><span>(<\/span><span>E<\/span><span>.<\/span><span>Foo<\/span><span>); <\/span><span>\/\/ works<\/span>\r\n<span>takeValue<\/span><span>(<\/span><span>123<\/span><span>); <\/span><span>\/\/ error!<\/span>\r\n<\/code><\/pre>\n<p>It wasn&#8217;t until TypeScript 2.0 introduced enum literal types that enums got a bit more special.\nEnum literal types gave each enum member its own type, and turned the enum itself into a <em>union<\/em> of each member type.\nThey also allowed us to refer to only a subset of the types of an enum, and to narrow away those types.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ Color is like a union of Red | Orange | Yellow | Green | Blue | Violet<\/span>\r\n<span>enum<\/span><span> <\/span><span>Color<\/span><span> {<\/span>\r\n<span>    <\/span><span>Red<\/span><span>, <\/span><span>Orange<\/span><span>, <\/span><span>Yellow<\/span><span>, <\/span><span>Green<\/span><span>, <\/span><span>Blue<\/span><span>, <\/span><span>\/* Indigo *\/<\/span><span>, <\/span><span>Violet<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ Each enum member has its own type that we can refer to!<\/span>\r\n<span>type<\/span><span> <\/span><span>PrimaryColor<\/span><span> = <\/span><span>Color<\/span><span>.<\/span><span>Red<\/span><span> | <\/span><span>Color<\/span><span>.<\/span><span>Green<\/span><span> | <\/span><span>Color<\/span><span>.<\/span><span>Blue<\/span><span>;<\/span>\r\n\r\n<span>function<\/span><span> <\/span><span>isPrimaryColor<\/span><span>(<\/span><span>c<\/span><span>: <\/span><span>Color<\/span><span>): <\/span><span>c<\/span><span> <\/span><span>is<\/span><span> <\/span><span>PrimaryColor<\/span><span> {<\/span>\r\n<span>    <\/span><span>\/\/ Narrowing literal types can catch bugs.<\/span>\r\n<span>    <\/span><span>\/\/ TypeScript will error here because<\/span>\r\n<span>    <\/span><span>\/\/ we'll end up comparing 'Color.Red' to 'Color.Green'.<\/span>\r\n<span>    <\/span><span>\/\/ We meant to use ||, but accidentally wrote &amp;&amp;.<\/span>\r\n<span>    <\/span><span>return<\/span><span> <\/span><span>c<\/span><span> === <\/span><span>Color<\/span><span>.<\/span><span>Red<\/span><span> &amp;&amp; <\/span><span>c<\/span><span> === <\/span><span>Color<\/span><span>.<\/span><span>Green<\/span><span> &amp;&amp; <\/span><span>c<\/span><span> === <\/span><span>Color<\/span><span>.<\/span><span>Blue<\/span><span>;<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>One issue with giving each enum member its own type was that those types were in some part associated with the actual value of the member.\nIn some cases it&#8217;s not possible to compute that value &#8211; for instance, an enum member could be initialized by a function call.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>enum<\/span><span> <\/span><span>E<\/span><span> {<\/span>\r\n<span>    <\/span><span>Blah<\/span><span> = <\/span><span>Math<\/span><span>.<\/span><span>random<\/span><span>()<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>Whenever TypeScript ran into these issues, it would quietly back out and use the old enum strategy.\nThat meant giving up all the advantages of unions and literal types.<\/p>\n<p>TypeScript 5.0 manages to make all enums into union enums by creating a unique type for each computed member.\nThat means that all enums can now be narrowed and have their members referenced as types as well.<\/p>\n<p>For more details on this change, you can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50528\">read the specifics on GitHub<\/a>.<\/p>\n<h2><code>--moduleResolution bundler<\/code><\/h2>\n<p>TypeScript 4.7 introduced the <code>node16<\/code> and <code>nodenext<\/code> options for its <code>--module<\/code> and <code>--moduleResolution<\/code> settings.\nThe intent of these options was to better model the precise lookup rules for ECMAScript modules in Node.js;\nhowever, this mode has many restrictions that other tools don&#8217;t really enforce.<\/p>\n<p>For example, in an ECMAScript module in Node.js, any relative import needs to include a file extension.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ entry.mjs<\/span>\r\n<span>import<\/span><span> <\/span><span>*<\/span><span> <\/span><span>as<\/span><span> <\/span><span>utils<\/span><span> <\/span><span>from<\/span><span> <\/span><span>&quot;.\/utils&quot;<\/span><span>;     <\/span><span>\/\/ \u274c wrong - we need to include the file extension.<\/span>\r\n\r\n<span>import<\/span><span> <\/span><span>*<\/span><span> <\/span><span>as<\/span><span> <\/span><span>utils<\/span><span> <\/span><span>from<\/span><span> <\/span><span>&quot;.\/utils.mjs&quot;<\/span><span>; <\/span><span>\/\/ \u2705 works<\/span>\r\n<\/code><\/pre>\n<p>There are certain reasons for this in Node.js and the browser &#8211; it makes file lookups faster and works better for naive file servers.\nBut for many developers using tools like bundlers, the <code>node16<\/code>\/<code>nodenext<\/code> settings were cumbersome because bundlers don&#8217;t have most of these restrictions.\nIn some ways, the <code>node<\/code> resolution mode was better for anyone using a bundler.<\/p>\n<p>But in some ways, the original <code>node<\/code> resolution mode was already out of date.\nMost modern bundlers use a fusion of the ECMAScript module and CommonJS lookup rules in Node.js.\nFor example, extensionless imports work just fine like in CommonJS, but when looking through the <a href=\"https:\/\/nodejs.org\/api\/packages.html#nested-conditions\"><code>export<\/code> conditions<\/a> of a package, they&#8217;ll prefer an <code>import<\/code> condition just like in an ECMAScript file.<\/p>\n<p>To model how bundlers work, TypeScript now introduces a new strategy: <code>--moduleResolution bundler<\/code>.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>{<\/span>\r\n<span>    <\/span><span>&quot;compilerOptions&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>&quot;target&quot;<\/span><span>: <\/span><span>&quot;esnext&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>&quot;moduleResolution&quot;<\/span><span>: <\/span><span>&quot;bundler&quot;<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>If you are using a modern bundler like Vite, esbuild, swc, Webpack, Parcel, and others that implement a hybrid lookup strategy, the new <code>bundler<\/code> option should be a good fit for you.<\/p>\n<p>On the other hand, if you&#8217;re writing a library that&#8217;s meant to be published on npm, using the <code>bundler<\/code> option can hide compatibility issues that may arise for your users who <em>aren&#8217;t<\/em> using a bundler.\nSo in these cases, using the <code>node16<\/code> or <code>nodenext<\/code> resolution options is likely to be a better path.<\/p>\n<p>To read more on <code>--moduleResolution bundler<\/code>, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51669\">take a look at the implementing pull request<\/a>.<\/p>\n<h2>Resolution Customization Flags<\/h2>\n<p>JavaScript tooling may now model &quot;hybrid&quot; resolution rules, like in the <code>bundler<\/code> mode we described above.\nBecause tools may differ in their support slightly, TypeScript 5.0 provides ways to enable or disable a few features that may or may not work with your configuration.<\/p>\n<h3><code>allowImportingTsExtensions<\/code><\/h3>\n<p><code>--allowImportingTsExtensions<\/code> allows TypeScript files to import each other with a TypeScript-specific extension like <code>.ts<\/code>, <code>.mts<\/code>, or <code>.tsx<\/code>.<\/p>\n<p>This flag is only allowed when <code>--noEmit<\/code> or <code>--emitDeclarationOnly<\/code> is enabled, since these import paths would not be resolvable at runtime in JavaScript output files.\nThe expectation here is that your resolver (e.g. your bundler, a runtime, or some other tool) is going to make these imports between <code>.ts<\/code> files work.<\/p>\n<h3><code>resolvePackageJsonExports<\/code><\/h3>\n<p><code>--resolvePackageJsonExports<\/code> forces TypeScript to consult <a href=\"https:\/\/nodejs.org\/api\/packages.html#exports\">the <code>exports<\/code> field of <code>package.json<\/code> files<\/a> if it ever reads from a package in <code>node_modules<\/code>.<\/p>\n<p>This option defaults to <code>true<\/code> under the <code>node16<\/code>, <code>nodenext<\/code>, and <code>bundler<\/code> options for <code>--moduleResolution<\/code>.<\/p>\n<h3><code>resolvePackageJsonImports<\/code><\/h3>\n<p><code>--resolvePackageJsonImports<\/code> forces TypeScript to consult <a href=\"https:\/\/nodejs.org\/api\/packages.html#imports\">the <code>imports<\/code> field of <code>package.json<\/code> files<\/a> when performing a lookup that starts with <code>#<\/code> from a file whose ancestor directory contains a <code>package.json<\/code>.<\/p>\n<p>This option defaults to <code>true<\/code> under the <code>node16<\/code>, <code>nodenext<\/code>, and <code>bundler<\/code> options for <code>--moduleResolution<\/code>.<\/p>\n<h3><code>allowArbitraryExtensions<\/code><\/h3>\n<p>In TypeScript 5.0, when an import path ends in an extension that isn&#8217;t a known JavaScript or TypeScript file extension, the compiler will look for a declaration file for that path in the form of <code>{file basename}.d.{extension}.ts<\/code>.\nFor example, if you are using a CSS loader in a bundler project, you might want to write (or generate) declaration files for those stylesheets:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/* app.css *\/<\/span>\r\n<span>.cookie-banner<\/span><span> {<\/span>\r\n<span>  <\/span><span>display<\/span><span>: <\/span><span>none<\/span><span>;<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ app.d.css.ts<\/span>\r\n<span>declare<\/span><span> <\/span><span>const<\/span><span> <\/span><span>css<\/span><span>: {<\/span>\r\n<span>  <\/span><span>cookieBanner<\/span><span>: <\/span><span>string<\/span><span>;<\/span>\r\n<span>};<\/span>\r\n<span>export<\/span><span> <\/span><span>default<\/span><span> <\/span><span>css<\/span><span>;<\/span>\r\n<\/code><\/pre>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ App.tsx<\/span>\r\n<span>import<\/span><span> <\/span><span>styles<\/span><span> <\/span><span>from<\/span><span> <\/span><span>&quot;.\/app.css&quot;<\/span><span>;<\/span>\r\n\r\n<span>styles<\/span><span>.<\/span><span>cookieBanner<\/span><span>; <\/span><span>\/\/ string<\/span>\r\n<\/code><\/pre>\n<p>By default, this import will raise an error to let you know that TypeScript doesn&#8217;t understand this file type and your runtime might not support importing it.\nBut if you&#8217;ve configured your runtime or bundler to handle it, you can suppress the error with the new <code>--allowArbitraryExtensions<\/code> compiler option.<\/p>\n<p>Note that historically, a similar effect has often been achievable by adding a declaration file named <code>app.css.d.ts<\/code> instead of <code>app.d.css.ts<\/code> &#8211; however, this just worked through Node&#8217;s <code>require<\/code> resolution rules for CommonJS.\nStrictly speaking, the former is interpreted as a declaration file for a JavaScript file named <code>app.css.js<\/code>.\nBecause relative files imports need to include extensions in Node&#8217;s ESM support, TypeScript would error on our example in an ESM file under <code>--moduleResolution node16<\/code> or <code>nodenext<\/code>.<\/p>\n<p>For more information, read up <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/50133\">the proposal for this feature<\/a> and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51435\">its corresponding pull request<\/a>.<\/p>\n<h3><code>customConditions<\/code><\/h3>\n<p><code>--customConditions<\/code> takes a list of additional <a href=\"https:\/\/nodejs.org\/api\/packages.html#nested-conditions\">conditions<\/a> that should succeed when TypeScript resolves from an [<code>exports<\/code>] or (<a href=\"https:\/\/nodejs.org\/api\/packages.html#exports\">https:\/\/nodejs.org\/api\/packages.html#exports<\/a>) or <a href=\"https:\/\/nodejs.org\/api\/packages.html#imports\"><code>imports<\/code><\/a> field of a <code>package.json<\/code>.\nThese conditions are added to whatever existing conditions a resolver will use by default.<\/p>\n<p>For example, when this field is set in a <code>tsconfig.json<\/code> as so:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>{<\/span>\r\n<span>    <\/span><span>&quot;compilerOptions&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>&quot;target&quot;<\/span><span>: <\/span><span>&quot;es2022&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>&quot;moduleResolution&quot;<\/span><span>: <\/span><span>&quot;bundler&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>&quot;customConditions&quot;<\/span><span>: [<\/span><span>&quot;my-condition&quot;<\/span><span>]<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>Any time an <code>exports<\/code> or <code>imports<\/code> field is referenced in <code>package.json<\/code>, TypeScript will consider conditions called <code>my-condition<\/code>.<\/p>\n<p>So when importing from a package with the following <code>package.json<\/code><\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>{<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>    <\/span><span>&quot;exports&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>&quot;.&quot;<\/span><span>: {<\/span>\r\n<span>            <\/span><span>&quot;my-condition&quot;<\/span><span>: <\/span><span>&quot;.\/foo.mjs&quot;<\/span><span>,<\/span>\r\n<span>            <\/span><span>&quot;node&quot;<\/span><span>: <\/span><span>&quot;.\/bar.mjs&quot;<\/span><span>,<\/span>\r\n<span>            <\/span><span>&quot;import&quot;<\/span><span>: <\/span><span>&quot;.\/baz.mjs&quot;<\/span><span>,<\/span>\r\n<span>            <\/span><span>&quot;require&quot;<\/span><span>: <\/span><span>&quot;.\/biz.mjs&quot;<\/span>\r\n<span>        }<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>TypeScript will try to look for files corresponding to <code>foo.mjs<\/code>.<\/p>\n<p>This field is only valid under the <code>node16<\/code>, <code>nodenext<\/code>, and <code>bundler<\/code> options for <code>--moduleResolution<\/code><\/p>\n<h2><code>--verbatimModuleSyntax<\/code><\/h2>\n<p>By default, TypeScript does something called <em>import elision<\/em>.\nBasically, if you write something like<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>import<\/span><span> { <\/span><span>Car<\/span><span> } <\/span><span>from<\/span><span> <\/span><span>&quot;.\/car&quot;<\/span><span>;<\/span>\r\n\r\n<span>export<\/span><span> <\/span><span>function<\/span><span> <\/span><span>drive<\/span><span>(<\/span><span>car<\/span><span>: <\/span><span>Car<\/span><span>) {<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>TypeScript detects that you&#8217;re only using an import for types and drops the import entirely.\nYour output JavaScript might look something like this:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>export<\/span><span> <\/span><span>function<\/span><span> <\/span><span>drive<\/span><span>(<\/span><span>car<\/span><span>) {<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>Most of the time this is good, because if <code>Car<\/code> isn&#8217;t a value that&#8217;s exported from <code>.\/car<\/code>, we&#8217;ll get a runtime error.<\/p>\n<p>But it does add a layer of complexity for certain edge cases.\nFor example, notice there&#8217;s no statement like <code>import &quot;.\/car&quot;;<\/code> &#8211; the import was dropped entirely.\nThat actually makes a difference for modules that have side effects or not.<\/p>\n<p>TypeScript&#8217;s emit strategy for JavaScript also has another few layers of complexity &#8211; import elision isn&#8217;t always just driven by how an import is used &#8211; it often consults how a value is declared as well.\nSo it&#8217;s not always clear whether code like the following<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>export<\/span><span> { <\/span><span>Car<\/span><span> } <\/span><span>from<\/span><span> <\/span><span>&quot;.\/car&quot;<\/span><span>;<\/span>\r\n<\/code><\/pre>\n<p>should be preserved or dropped.\nIf <code>Car<\/code> is declared with something like a <code>class<\/code>, then it can be preserved in the resulting JavaScript file.\nBut if <code>Car<\/code> is only declared as a <code>type<\/code> alias or <code>interface<\/code>, then the JavaScript file shouldn&#8217;t export <code>Car<\/code> at all.<\/p>\n<p>While TypeScript might be able to make these emit decisions based on information from across files, not every compiler can.<\/p>\n<p>The <code>type<\/code> modifier on imports and exports helps with these situations a bit.\nWe can make it explicit whether an import or export is only being used for type analysis, and can be dropped entirely in JavaScript files by using the <code>type<\/code> modifier.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ This statement can be dropped entirely in JS output<\/span>\r\n<span>import<\/span><span> <\/span><span>type<\/span><span> <\/span><span>*<\/span><span> <\/span><span>as<\/span><span> <\/span><span>car<\/span><span> <\/span><span>from<\/span><span> <\/span><span>&quot;.\/car&quot;<\/span><span>;<\/span>\r\n\r\n<span>\/\/ The named import\/export 'Car' can be dropped in JS output<\/span>\r\n<span>import<\/span><span> { <\/span><span>type<\/span><span> <\/span><span>Car<\/span><span> } <\/span><span>from<\/span><span> <\/span><span>&quot;.\/car&quot;<\/span><span>;<\/span>\r\n<span>export<\/span><span> { <\/span><span>type<\/span><span> <\/span><span>Car<\/span><span> } <\/span><span>from<\/span><span> <\/span><span>&quot;.\/car&quot;<\/span><span>;<\/span>\r\n<\/code><\/pre>\n<p><code>type<\/code> modifiers are not quite useful on their own &#8211; by default, module elision will still drop imports, and nothing forces you to make the distinction between <code>type<\/code> and plain imports and exports.\nSo TypeScript has the flag <code>--importsNotUsedAsValues<\/code> to make sure you use the <code>type<\/code> modifier, <code>--preserveValueImports<\/code> to prevent <em>some<\/em> module elision behavior, and <code>--isolatedModules<\/code> to make sure that your TypeScript code works across different compilers.\nUnfortunately, understanding the fine details of those 3 flags is hard, and there are still some edge cases with unexpected behavior.<\/p>\n<p>TypeScript 5.0 introduces a new option called <code>--verbatimModuleSyntax<\/code> to simplify the situation.\nThe rules are much simpler &#8211; any imports or exports without a <code>type<\/code> modifier are left around.\nAnything that uses the <code>type<\/code> modifier is dropped entirely.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ Erased away entirely.<\/span>\r\n<span>import<\/span><span> <\/span><span>type<\/span><span> { <\/span><span>A<\/span><span> } <\/span><span>from<\/span><span> <\/span><span>&quot;a&quot;<\/span><span>;<\/span>\r\n\r\n<span>\/\/ Rewritten to 'import { b } from &quot;bcd&quot;;'<\/span>\r\n<span>import<\/span><span> { <\/span><span>b<\/span><span>, <\/span><span>type<\/span><span> <\/span><span>c<\/span><span>, <\/span><span>type<\/span><span> <\/span><span>d<\/span><span> } <\/span><span>from<\/span><span> <\/span><span>&quot;bcd&quot;<\/span><span>;<\/span>\r\n\r\n<span>\/\/ Rewritten to 'import {} from &quot;xyz&quot;;'<\/span>\r\n<span>import<\/span><span> { <\/span><span>type<\/span><span> <\/span><span>xyz<\/span><span> } <\/span><span>from<\/span><span> <\/span><span>&quot;xyz&quot;<\/span><span>;<\/span>\r\n<\/code><\/pre>\n<p>With this new option, what you see is what you get.<\/p>\n<p>That does have some implications when it comes to module interop though.\nUnder this flag, ECMAScript <code>import<\/code>s and <code>export<\/code>s won&#8217;t be rewritten to <code>require<\/code> calls when your settings or file extension implied a different module system.\nInstead, you&#8217;ll get an error.\nIf you need to emit code that uses <code>require<\/code> and <code>module.exports<\/code>, you&#8217;ll have to use TypeScript&#8217;s module syntax that predates ES2015:<\/p>\n<table>\n<thead>\n<tr>\n<th>Input TypeScript<\/th>\n<th>Output JavaScript<\/th>\n<\/tr>\n<\/thead>\n<tr>\n<td>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>import<\/span><span> <\/span><span>foo<\/span><span> = <\/span><span>require<\/span><span>(<\/span><span>&quot;foo&quot;<\/span><span>);<\/span>\r\n<\/code><\/pre>\n<\/td>\n<td>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>const<\/span><span> <\/span><span>foo<\/span><span> = <\/span><span>require<\/span><span>(<\/span><span>&quot;foo&quot;<\/span><span>);<\/span>\r\n<\/code><\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>foo<\/span><span>() {}<\/span>\r\n<span>function<\/span><span> <\/span><span>bar<\/span><span>() {}<\/span>\r\n<span>function<\/span><span> <\/span><span>baz<\/span><span>() {}<\/span>\r\n\r\n<span>export<\/span><span> = {<\/span>\r\n<span>    <\/span><span>foo<\/span><span>,<\/span>\r\n<span>    <\/span><span>bar<\/span><span>,<\/span>\r\n<span>    <\/span><span>baz<\/span>\r\n<span>};<\/span>\r\n<\/code><\/pre>\n<\/td>\n<td>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>foo<\/span><span>() {}<\/span>\r\n<span>function<\/span><span> <\/span><span>bar<\/span><span>() {}<\/span>\r\n<span>function<\/span><span> <\/span><span>baz<\/span><span>() {}<\/span>\r\n\r\n<span>module<\/span><span>.<\/span><span>exports<\/span><span> = {<\/span>\r\n<span>    <\/span><span>foo<\/span><span>,<\/span>\r\n<span>    <\/span><span>bar<\/span><span>,<\/span>\r\n<span>    <\/span><span>baz<\/span>\r\n<span>};<\/span>\r\n<\/code><\/pre>\n<\/td>\n<\/tr>\n<\/table>\n<p>While this is a limitation, it does help make some issues more obvious.\nFor example, it&#8217;s very common to forget to set the <a href=\"https:\/\/nodejs.org\/api\/packages.html#type\"><code>type<\/code> field in <code>package.json<\/code><\/a> under <code>--module node16<\/code>.\nAs a result, developers would start writing CommonJS modules instead of an ES modules without realizing it, giving surprising lookup rules and JavaScript output.\nThis new flag ensures that you&#8217;re intentional about the file type you&#8217;re using because the syntax is intentionally different.<\/p>\n<p>Because <code>--verbatimModuleSyntax<\/code> provides a more consistent story than <code>--importsNotUsedAsValues<\/code> and <code>--preserveValueImports<\/code>, those two existing flags are being deprecated in its favor.<\/p>\n<p>For more details, read up on <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/52203\">the original pull request<\/a> and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/51479\">its proposal issue<\/a>.<\/p>\n<h2>Support for <code>export type *<\/code><\/h2>\n<p>When TypeScript 3.8 introduced type-only imports, the new syntax wasn&#8217;t allowed on <code>export * from &quot;module&quot;<\/code> or <code>export * as ns from &quot;module&quot;<\/code> re-exports. TypeScript 5.0 adds support for both of these forms:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ models\/vehicles.ts<\/span>\r\n<span>export<\/span><span> <\/span><span>class<\/span><span> <\/span><span>Spaceship<\/span><span> {<\/span>\r\n<span>  <\/span><span>\/\/ ...<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ models\/index.ts<\/span>\r\n<span>export<\/span><span> <\/span><span>type<\/span><span> <\/span><span>*<\/span><span> <\/span><span>as<\/span><span> <\/span><span>vehicles<\/span><span> <\/span><span>from<\/span><span> <\/span><span>&quot;.\/vehicles&quot;<\/span><span>;<\/span>\r\n\r\n<span>\/\/ main.ts<\/span>\r\n<span>import<\/span><span> { <\/span><span>vehicles<\/span><span> } <\/span><span>from<\/span><span> <\/span><span>&quot;.\/models&quot;<\/span><span>;<\/span>\r\n\r\n<span>function<\/span><span> <\/span><span>takeASpaceship<\/span><span>(<\/span><span>s<\/span><span>: <\/span><span>vehicles<\/span><span>.<\/span><span>Spaceship<\/span><span>) {<\/span>\r\n<span>  <\/span><span>\/\/ \u2705 ok - `vehicles` only used in a type position<\/span>\r\n<span>}<\/span>\r\n\r\n<span>function<\/span><span> <\/span><span>makeASpaceship<\/span><span>() {<\/span>\r\n<span>  <\/span><span>return<\/span><span> <\/span><span>new<\/span><span> <\/span><span>vehicles<\/span><span>.<\/span><span>Spaceship<\/span><span>();<\/span>\r\n<span>  <\/span><span>\/\/         ^^^^^^^^<\/span>\r\n<span>  <\/span><span>\/\/ 'vehicles' cannot be used as a value because it was exported using 'export type'.<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>You can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/52217\">read more about the implementation here<\/a>.<\/p>\n<h2><code>@satisfies<\/code> Support in JSDoc<\/h2>\n<p>TypeScript 4.9 introduced the <code>satisfies<\/code> operator.\nIt made sure that the type of an expression was compatible, without affecting the type itself.\nFor example, let&#8217;s take the following code:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>interface<\/span><span> <\/span><span>CompilerOptions<\/span><span> {<\/span>\r\n<span>    <\/span><span>strict<\/span><span>?: <\/span><span>boolean<\/span><span>;<\/span>\r\n<span>    <\/span><span>outDir<\/span><span>?: <\/span><span>string<\/span><span>;<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>}<\/span>\r\n\r\n<span>interface<\/span><span> <\/span><span>ConfigSettings<\/span><span> {<\/span>\r\n<span>    <\/span><span>compilerOptions<\/span><span>?: <\/span><span>CompilerOptions<\/span><span>;<\/span>\r\n<span>    <\/span><span>extends<\/span><span>?: <\/span><span>string<\/span><span> | <\/span><span>string<\/span><span>[];<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>}<\/span>\r\n\r\n<span>let<\/span><span> <\/span><span>myConfigSettings<\/span><span> = {<\/span>\r\n<span>    <\/span><span>compilerOptions:<\/span><span> {<\/span>\r\n<span>        <\/span><span>strict:<\/span><span> <\/span><span>true<\/span><span>,<\/span>\r\n<span>        <\/span><span>outDir:<\/span><span> <\/span><span>&quot;..\/lib&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>\/\/ ...<\/span>\r\n<span>    },<\/span>\r\n\r\n<span>    <\/span><span>extends:<\/span><span> [<\/span>\r\n<span>        <\/span><span>&quot;@tsconfig\/strictest\/tsconfig.json&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>&quot;..\/..\/..\/tsconfig.base.json&quot;<\/span>\r\n<span>    ],<\/span>\r\n\r\n<span>} <\/span><span>satisfies<\/span><span> <\/span><span>ConfigSettings<\/span><span>;<\/span>\r\n<\/code><\/pre>\n<p>Here, TypeScript knows that <code>myConfigSettings.extends<\/code> was declared with an array &#8211; because while <code>satisfies<\/code> validated the type of our object, it didn&#8217;t bluntly change it to <code>ConfigSettings<\/code> and lose information.\nSo if we want to map over <code>extends<\/code>, that&#8217;s fine.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>declare<\/span><span> <\/span><span>function<\/span><span> <\/span><span>resolveConfig<\/span><span>(<\/span><span>configPath<\/span><span>: <\/span><span>string<\/span><span>): <\/span><span>CompilerOptions<\/span><span>;<\/span>\r\n\r\n<span>let<\/span><span> <\/span><span>inheritedConfigs<\/span><span> = <\/span><span>myConfigSettings<\/span><span>.<\/span><span>extends<\/span><span>.<\/span><span>map<\/span><span>(<\/span><span>resolveConfig<\/span><span>);<\/span>\r\n<\/code><\/pre>\n<p>This was helpful for TypeScript users, but plenty of people use TypeScript to type-check their JavaScript code using JSDoc annotations.\nThat&#8217;s why TypeScript 5.0 is supporting a new JSDoc tag called <code>@satisfies<\/code> that does exactly the same thing.<\/p>\n<p><code>\/** @satisfies *\/<\/code> can catch type mismatches:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ @ts-check<\/span>\r\n\r\n<span>\/**<\/span>\r\n<span> * <\/span><span>@typedef<\/span><span> <\/span><span>CompilerOptions<\/span>\r\n<span> * <\/span><span>@prop<\/span><span> <\/span><span>{boolean}<\/span><span> <\/span><span>[strict]<\/span>\r\n<span> * <\/span><span>@prop<\/span><span> <\/span><span>{string}<\/span><span> <\/span><span>[outDir]<\/span>\r\n<span> *\/<\/span>\r\n\r\n<span>\/**<\/span>\r\n<span> * <\/span><span>@satisfies<\/span><span> {CompilerOptions}<\/span>\r\n<span> *\/<\/span>\r\n<span>let<\/span><span> <\/span><span>myCompilerOptions<\/span><span> = {<\/span>\r\n<span>    <\/span><span>outdir:<\/span><span> <\/span><span>&quot;..\/lib&quot;<\/span><span>,<\/span>\r\n<span>\/\/  ~~~~~~ oops! we meant outDir<\/span>\r\n<span>};<\/span>\r\n<\/code><\/pre>\n<p>But it will preserve the original type of our expressions, allowing us to use our values more precisely later on in our code.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ @ts-check<\/span>\r\n\r\n<span>\/**<\/span>\r\n<span> * <\/span><span>@typedef<\/span><span> <\/span><span>CompilerOptions<\/span>\r\n<span> * <\/span><span>@prop<\/span><span> <\/span><span>{boolean}<\/span><span> <\/span><span>[strict]<\/span>\r\n<span> * <\/span><span>@prop<\/span><span> <\/span><span>{string}<\/span><span> <\/span><span>[outDir]<\/span>\r\n<span> *\/<\/span>\r\n\r\n<span>\/**<\/span>\r\n<span> * <\/span><span>@typedef<\/span><span> <\/span><span>ConfigSettings<\/span>\r\n<span> * <\/span><span>@prop<\/span><span> <\/span><span>{CompilerOptions}<\/span><span> <\/span><span>[compilerOptions]<\/span>\r\n<span> * <\/span><span>@prop<\/span><span> <\/span><span>{string | string[]}<\/span><span> <\/span><span>[extends]<\/span>\r\n<span> *\/<\/span>\r\n\r\n\r\n<span>\/**<\/span>\r\n<span> * <\/span><span>@satisfies<\/span><span> {ConfigSettings}<\/span>\r\n<span> *\/<\/span>\r\n<span>let<\/span><span> <\/span><span>myConfigSettings<\/span><span> = {<\/span>\r\n<span>    <\/span><span>compilerOptions:<\/span><span> {<\/span>\r\n<span>        <\/span><span>strict:<\/span><span> <\/span><span>true<\/span><span>,<\/span>\r\n<span>        <\/span><span>outDir:<\/span><span> <\/span><span>&quot;..\/lib&quot;<\/span><span>,<\/span>\r\n<span>    },<\/span>\r\n<span>    <\/span><span>extends:<\/span><span> [<\/span>\r\n<span>        <\/span><span>&quot;@tsconfig\/strictest\/tsconfig.json&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>&quot;..\/..\/..\/tsconfig.base.json&quot;<\/span>\r\n<span>    ],<\/span>\r\n<span>};<\/span>\r\n\r\n<span>let<\/span><span> <\/span><span>inheritedConfigs<\/span><span> = <\/span><span>myConfigSettings<\/span><span>.<\/span><span>extends<\/span><span>.<\/span><span>map<\/span><span>(<\/span><span>resolveConfig<\/span><span>);<\/span>\r\n<\/code><\/pre>\n<p><code>\/** @satisfies *\/<\/code> can also be used inline on any parenthesized expression.\nWe could have written <code>myConfigSettings<\/code> like this:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>let<\/span><span> <\/span><span>myConfigSettings<\/span><span> = <\/span><span>\/** <\/span><span>@satisfies<\/span><span> {ConfigSettings} *\/<\/span><span> ({<\/span>\r\n<span>    <\/span><span>compilerOptions:<\/span><span> {<\/span>\r\n<span>        <\/span><span>strict:<\/span><span> <\/span><span>true<\/span><span>,<\/span>\r\n<span>        <\/span><span>outDir:<\/span><span> <\/span><span>&quot;..\/lib&quot;<\/span><span>,<\/span>\r\n<span>    },<\/span>\r\n<span>    <\/span><span>extends:<\/span><span> [<\/span>\r\n<span>        <\/span><span>&quot;@tsconfig\/strictest\/tsconfig.json&quot;<\/span><span>,<\/span>\r\n<span>        <\/span><span>&quot;..\/..\/..\/tsconfig.base.json&quot;<\/span>\r\n<span>    ],<\/span>\r\n<span>});<\/span>\r\n<\/code><\/pre>\n<p>Why?\nWell, it usually makes more sense when you&#8217;re deeper in some other code, like a function call.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>compileCode<\/span><span>(<\/span><span>\/** <\/span><span>@satisfies<\/span><span> {ConfigSettings} *\/<\/span><span> ({<\/span>\r\n<span>    <\/span><span>\/\/ ...<\/span>\r\n<span>}));<\/span>\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51753\">This feature<\/a> was provided thanks to <a href=\"https:\/\/github.com\/a-tarasyuk\">Oleksandr Tarasiuk<\/a>!<\/p>\n<h2><code>@overload<\/code> Support in JSDoc<\/h2>\n<p>In TypeScript, you can specify overloads for a function.\nOverloads give us a way to say that a function can be called with different arguments, and possibly return different results.\nThey can restrict how callers can actually use our functions, and refine what results they&#8217;ll get back.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ Our overloads:<\/span>\r\n<span>function<\/span><span> <\/span><span>printValue<\/span><span>(<\/span><span>str<\/span><span>: <\/span><span>string<\/span><span>): <\/span><span>void<\/span><span>;<\/span>\r\n<span>function<\/span><span> <\/span><span>printValue<\/span><span>(<\/span><span>num<\/span><span>: <\/span><span>number<\/span><span>, <\/span><span>maxFractionDigits<\/span><span>?: <\/span><span>number<\/span><span>): <\/span><span>void<\/span><span>;<\/span>\r\n\r\n<span>\/\/ Our implementation:<\/span>\r\n<span>function<\/span><span> <\/span><span>printValue<\/span><span>(<\/span><span>value<\/span><span>: <\/span><span>string<\/span><span> | <\/span><span>number<\/span><span>, <\/span><span>maximumFractionDigits<\/span><span>?: <\/span><span>number<\/span><span>) {<\/span>\r\n<span>    <\/span><span>if<\/span><span> (<\/span><span>typeof<\/span><span> <\/span><span>value<\/span><span> === <\/span><span>&quot;number&quot;<\/span><span>) {<\/span>\r\n<span>        <\/span><span>const<\/span><span> <\/span><span>formatter<\/span><span> = <\/span><span>Intl<\/span><span>.<\/span><span>NumberFormat<\/span><span>(<\/span><span>&quot;en-US&quot;<\/span><span>, {<\/span>\r\n<span>            <\/span><span>maximumFractionDigits<\/span><span>,<\/span>\r\n<span>        });<\/span>\r\n<span>        <\/span><span>value<\/span><span> = <\/span><span>formatter<\/span><span>.<\/span><span>format<\/span><span>(<\/span><span>value<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>value<\/span><span>);<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>Here, we&#8217;ve said that <code>printValue<\/code> takes either a <code>string<\/code> or a <code>number<\/code> as its first argument.\nIf it takes a <code>number<\/code>, it can take a second argument to determine how many fractional digits we can print.<\/p>\n<p>TypeScript 5.0 now allows JSDoc to declare overloads with a new <code>@overload<\/code> tag.\nEach JSDoc comment with an <code>@overload<\/code> tag is treated as a distinct overload for the following function declaration.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ @ts-check<\/span>\r\n\r\n<span>\/**<\/span>\r\n<span> * <\/span><span>@overload<\/span>\r\n<span> * <\/span><span>@param<\/span><span> <\/span><span>{string}<\/span><span> <\/span><span>value<\/span>\r\n<span> * <\/span><span>@return<\/span><span> <\/span><span>{void}<\/span>\r\n<span> *\/<\/span>\r\n\r\n<span>\/**<\/span>\r\n<span> * <\/span><span>@overload<\/span>\r\n<span> * <\/span><span>@param<\/span><span> <\/span><span>{number}<\/span><span> <\/span><span>value<\/span>\r\n<span> * <\/span><span>@param<\/span><span> <\/span><span>{number}<\/span><span> <\/span><span>[maximumFractionDigits]<\/span>\r\n<span> * <\/span><span>@return<\/span><span> <\/span><span>{void}<\/span>\r\n<span> *\/<\/span>\r\n\r\n<span>\/**<\/span>\r\n<span> * <\/span><span>@param<\/span><span> <\/span><span>{string | number}<\/span><span> <\/span><span>value<\/span>\r\n<span> * <\/span><span>@param<\/span><span> <\/span><span>{number}<\/span><span> <\/span><span>[maximumFractionDigits]<\/span>\r\n<span> *\/<\/span>\r\n<span>function<\/span><span> <\/span><span>printValue<\/span><span>(<\/span><span>value<\/span><span>, <\/span><span>maximumFractionDigits<\/span><span>) {<\/span>\r\n<span>    <\/span><span>if<\/span><span> (<\/span><span>typeof<\/span><span> <\/span><span>value<\/span><span> === <\/span><span>&quot;number&quot;<\/span><span>) {<\/span>\r\n<span>        <\/span><span>const<\/span><span> <\/span><span>formatter<\/span><span> = <\/span><span>Intl<\/span><span>.<\/span><span>NumberFormat<\/span><span>(<\/span><span>&quot;en-US&quot;<\/span><span>, {<\/span>\r\n<span>            <\/span><span>maximumFractionDigits<\/span><span>,<\/span>\r\n<span>        });<\/span>\r\n<span>        <\/span><span>value<\/span><span> = <\/span><span>formatter<\/span><span>.<\/span><span>format<\/span><span>(<\/span><span>value<\/span><span>);<\/span>\r\n<span>    }<\/span>\r\n\r\n<span>    <\/span><span>console<\/span><span>.<\/span><span>log<\/span><span>(<\/span><span>value<\/span><span>);<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>Now regardless of whether we&#8217;re writing in a TypeScript or JavaScript file, TypeScript can let us know if we&#8217;ve called our functions incorrectly.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>\/\/ all allowed<\/span>\r\n<span>printValue<\/span><span>(<\/span><span>&quot;hello!&quot;<\/span><span>);<\/span>\r\n<span>printValue<\/span><span>(<\/span><span>123.45<\/span><span>);<\/span>\r\n<span>printValue<\/span><span>(<\/span><span>123.45<\/span><span>, <\/span><span>2<\/span><span>);<\/span>\r\n\r\n<span>printValue<\/span><span>(<\/span><span>&quot;hello!&quot;<\/span><span>, <\/span><span>123<\/span><span>); <\/span><span>\/\/ error!<\/span>\r\n<\/code><\/pre>\n<p>This new tag <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51234\">was implemented<\/a> thanks to <a href=\"https:\/\/github.com\/apendua\">Tomasz Lenarcik<\/a>.<\/p>\n<h2>Passing Emit-Specific Flags Under <code>--build<\/code><\/h2>\n<p>TypeScript now allows the following flags to be passed under <code>--build<\/code> mode<\/p>\n<ul>\n<li><code>--declaration<\/code><\/li>\n<li><code>--emitDeclarationOnly<\/code><\/li>\n<li><code>--declarationMap<\/code><\/li>\n<li><code>--sourceMap<\/code><\/li>\n<li><code>--inlineSourceMap<\/code><\/li>\n<\/ul>\n<p>This makes it way easier to customize certain parts of a build where you might have different development and production builds.<\/p>\n<p>For example, a development build of a library might not need to produce declaration files, but a production build would.\nA project can configure declaration emit to be off by default and simply be built with<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>tsc --build -p .\/my-project-dir<\/span>\r\n<\/code><\/pre>\n<p>Once you&#8217;re done iterating in the inner loop, a &quot;production&quot; build can just pass the <code>--declaration<\/code> flag.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>tsc --build -p .\/my-project-dir --declaration<\/span>\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51241\">More information on this change is available here<\/a>.<\/p>\n<h2>Case-Insensitive Import Sorting in Editors<\/h2>\n<p>In editors like Visual Studio and VS Code, TypeScript powers the experience for organizing and sorting imports and exports.\nOften though, there can be different interpretations of when a list is &quot;sorted&quot;.<\/p>\n<p>For example, is the following import list sorted?<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>import<\/span><span> {<\/span>\r\n<span>    <\/span><span>Toggle<\/span><span>,<\/span>\r\n<span>    <\/span><span>freeze<\/span><span>,<\/span>\r\n<span>    <\/span><span>toBoolean<\/span><span>,<\/span>\r\n<span>} <\/span><span>from<\/span><span> <\/span><span>&quot;.\/utils&quot;<\/span><span>;<\/span>\r\n<\/code><\/pre>\n<p>The answer might surprisingly be &quot;it depends&quot;.\nIf we <em>don&#8217;t<\/em> care about case-sensitivity, then this list is clearly not sorted.\nThe letter <code>f<\/code> comes before both <code>t<\/code> and <code>T<\/code>.<\/p>\n<p>But in most programming languages, sorting defaults to comparing the byte values of strings.\nThe way JavaScript compares strings means that <code>&quot;Toggle&quot;<\/code> always comes before <code>&quot;freeze&quot;<\/code> because according to the <a href=\"https:\/\/en.wikipedia.org\/wiki\/ASCII\">ASCII character encoding<\/a>, uppercase letters come before lowercase.\nSo from that perspective, the import list is sorted.<\/p>\n<p>TypeScript previously considered the import list to be sorted because it was doing a basic case-sensitive sort.\nThis could be a point of frustration for developers who preferred a case-<em>insensitive<\/em> ordering, or who used tools like ESLint which require to case-insensitive ordering by default.<\/p>\n<p>TypeScript now detects case sensitivity by default.\nThis means that TypeScript and tools like ESLint typically won&#8217;t &quot;fight&quot; each other over how to best sort imports.<\/p>\n<p>Our team has also been experimenting <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/52115\">with further sorting strategies which you can read about here<\/a>.\nThese options may eventually be configurable by editors.\nFor now, they are still unstable and experimental, and you can opt into them in VS Code today by using the <code>typescript.unstable<\/code> entry in your JSON options.\nBelow are all of the options you can try out (set to their defaults):<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>{<\/span>\r\n<span>    <\/span><span>&quot;typescript.unstable&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>\/\/ Should sorting be case-sensitive? Can be:<\/span>\r\n<span>        <\/span><span>\/\/ - true<\/span>\r\n<span>        <\/span><span>\/\/ - false<\/span>\r\n<span>        <\/span><span>\/\/ - &quot;auto&quot; (auto-detect)<\/span>\r\n<span>        <\/span><span>&quot;organizeImportsIgnoreCase&quot;<\/span><span>: <\/span><span>&quot;auto&quot;<\/span><span>,<\/span>\r\n\r\n<span>        <\/span><span>\/\/ Should sorting be &quot;ordinal&quot; and use code points or consider Unicode rules? Can be:<\/span>\r\n<span>        <\/span><span>\/\/ - &quot;ordinal&quot;<\/span>\r\n<span>        <\/span><span>\/\/ - &quot;unicode&quot;<\/span>\r\n<span>        <\/span><span>&quot;organizeImportsCollation&quot;<\/span><span>: <\/span><span>&quot;ordinal&quot;<\/span><span>,<\/span>\r\n\r\n<span>        <\/span><span>\/\/ Under `&quot;organizeImportsCollation&quot;: &quot;unicode&quot;`,<\/span>\r\n<span>        <\/span><span>\/\/ what is the current locale? Can be:<\/span>\r\n<span>        <\/span><span>\/\/ - [any other locale code]<\/span>\r\n<span>        <\/span><span>\/\/ - &quot;auto&quot; (use the editor's locale)<\/span>\r\n<span>        <\/span><span>&quot;organizeImportsLocale&quot;<\/span><span>: <\/span><span>&quot;en&quot;<\/span><span>,<\/span>\r\n\r\n<span>        <\/span><span>\/\/ Under `&quot;organizeImportsCollation&quot;: &quot;unicode&quot;`,<\/span>\r\n<span>        <\/span><span>\/\/ should upper-case letters or lower-case letters come first? Can be:<\/span>\r\n<span>        <\/span><span>\/\/ - false (locale-specific)<\/span>\r\n<span>        <\/span><span>\/\/ - &quot;upper&quot;<\/span>\r\n<span>        <\/span><span>\/\/ - &quot;lower&quot;<\/span>\r\n<span>        <\/span><span>&quot;organizeImportsCaseFirst&quot;<\/span><span>: <\/span><span>false<\/span><span>,<\/span>\r\n\r\n<span>        <\/span><span>\/\/ Under `&quot;organizeImportsCollation&quot;: &quot;unicode&quot;`,<\/span>\r\n<span>        <\/span><span>\/\/ do runs of numbers get compared numerically (i.e. &quot;a1&quot; &lt; &quot;a2&quot; &lt; &quot;a100&quot;)? Can be:<\/span>\r\n<span>        <\/span><span>\/\/ - true<\/span>\r\n<span>        <\/span><span>\/\/ - false<\/span>\r\n<span>        <\/span><span>&quot;organizeImportsNumericCollation&quot;<\/span><span>: <\/span><span>true<\/span><span>,<\/span>\r\n\r\n<span>        <\/span><span>\/\/ Under `&quot;organizeImportsCollation&quot;: &quot;unicode&quot;`,<\/span>\r\n<span>        <\/span><span>\/\/ do letters with accent marks\/diacritics get sorted distinctly<\/span>\r\n<span>        <\/span><span>\/\/ from their &quot;base&quot; letter (i.e. is \u00e9 different from e)? Can be<\/span>\r\n<span>        <\/span><span>\/\/ - true<\/span>\r\n<span>        <\/span><span>\/\/ - false<\/span>\r\n<span>        <\/span><span>&quot;organizeImportsAccentCollation&quot;<\/span><span>: <\/span><span>true<\/span>\r\n<span>    },<\/span>\r\n<span>    <\/span><span>&quot;javascript.unstable&quot;<\/span><span>: {<\/span>\r\n<span>        <\/span><span>\/\/ same options valid here...<\/span>\r\n<span>    },<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>You can read more details on <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51733\">the original work for auto-detecting and specifying case-insensitivity<\/a>, followed by <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/52115\">the broader set of options<\/a>.<\/p>\n<h2>Exhaustive <code>switch<\/code>\/<code>case<\/code> Completions<\/h2>\n<p>When writing a <code>switch<\/code> statement, TypeScript now detects when the value being checked has a literal type.\nIf so, it will offer a completion that scaffolds out each uncovered <code>case<\/code>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2023\/03\/exhaustiveCaseCompletions-5.0-stable-1.gif\" alt=\"A set of  statements generated through auto-completion based on literal types.\"><\/p>\n<p>You can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50996\">see specifics of the implementation on GitHub<\/a>.<\/p>\n<h2>Speed, Memory, and Package Size Optimizations<\/h2>\n<p>TypeScript 5.0 contains lots of powerful changes across our code structure, our data structures, and algorithmic implementations.\nWhat these all mean is that your entire experience should be faster &#8211; not just running TypeScript, but even installing it.<\/p>\n<p>Here are a few interesting wins in speed and size that we&#8217;ve been able to capture relative to TypeScript 4.9.<\/p>\n<table>\n<thead>\n<tr>\n<th>Scenario<\/th>\n<th>Time or Size Relative to TS 4.9<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>material-ui build time<\/td>\n<td>90%<\/td>\n<\/tr>\n<tr>\n<td>TypeScript Compiler startup time<\/td>\n<td>89%<\/td>\n<\/tr>\n<tr>\n<td>Playwright build time<\/td>\n<td>88%<\/td>\n<\/tr>\n<tr>\n<td>TypeScript Compiler self-build time<\/td>\n<td>87%<\/td>\n<\/tr>\n<tr>\n<td>Outlook Web build time<\/td>\n<td>82%<\/td>\n<\/tr>\n<tr>\n<td>VS Code build time<\/td>\n<td>80%<\/td>\n<\/tr>\n<tr>\n<td>typescript npm Package Size<\/td>\n<td>59%<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2023\/03\/speed-5.0-stable-2.png\" alt=\"Chart of build\/run times TypeScript 5.0 relative to TypeScript 4.9: material-ui docs build time: 90%; Playwright build time: 88%; tsc startup time: 87%; tsc build time: 87%; Outlook Web build time: 82%; VS Code build time: 80%\"><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2023\/03\/size-5.0-stable-1.png\" alt=\"Chart of package size on npm between TypeScript 4.9 and 5.0. 4.9 package size is 63.8 MB, 5.0 package size is 37.4 MB.\"><\/p>\n<p>How?\nThere are a few notable improvements we&#8217;d like to give more details on in the future.\nBut we won&#8217;t make you wait for that blog post.<\/p>\n<p>First off, we recently migrated TypeScript from namespaces to modules, allowing us to leverage modern build tooling that can perform optimizations like scope hoisting.\nUsing this tooling, revisiting our packaging strategy, and removing some deprecated code has shaved off about 26.4 MB from TypeScript 4.9&#8217;s 63.8 MB package size.\nIt also brought us a notable speed-up through direct function calls.\nWe put together <a href=\"https:\/\/devblogs.microsoft.com\/typescript\/typescripts-migration-to-modules\/\">a detailed write-up about our migration to modules here<\/a>.<\/p>\n<p>TypeScript also added more uniformity to internal object types within the compiler, and also slimmed the data stored on some of these object types as well.\nThis reduced polymorphic operations, while balancing out the increase in memory usage that came from making our object shapes more uniform.<\/p>\n<p>We&#8217;ve also performed some caching when serializing information to strings.\nType display, which can happen as part of error reporting, declaration emit, code completions, and more, can end up being fairly expensive.\nTypeScript now caches some commonly used machinery to reuse across these operations.<\/p>\n<p>Another notable change we made that improved our parser was leveraging <code>var<\/code> to occasionally side-step the cost of using <code>let<\/code> and <code>const<\/code> across closures.\nThis improved some of our parsing performance.<\/p>\n<p>Overall, we expect most codebases should see speed improvements from TypeScript 5.0, and have consistently been able to reproduce wins between 10% to 20%.\nOf course this will depend on hardware and codebase characteristics, but we encourage you to try it out on your codebase today!<\/p>\n<p>For more information, see some of our notable optimizations:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51387\">Migrate to Modules<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51682\"><code>Node<\/code> Monomorphization<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/51880\"><code>Symbol<\/code> Monomorphization<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/52170\"><code>Identifier<\/code> Size Reduction<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/52382\"><code>Printer<\/code> Caching<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/52924\">Limited Usage of <code>var<\/code><\/a><\/li>\n<\/ul>\n<h2>Breaking Changes and Deprecations<\/h2>\n<h3>Runtime Requirements<\/h3>\n<p>TypeScript now targets ECMAScript 2018.\nThe TypeScript package has also set a minimum expected engine of 12.20.\nFor Node users, that means TypeScript 5.0 has a minimum version requirement of at least Node.js 12.20 and later.<\/p>\n<h3><code>lib.d.ts<\/code> Changes<\/h3>\n<p>Changes to how types for the DOM are generated might have an impact on existing code.\nNotably, certain properties have been converted from <code>number<\/code> to numeric literal types, and properties and methods for cut, copy, and paste event handling have been moved across interfaces.<\/p>\n<h3>API Breaking Changes<\/h3>\n<p>In TypeScript 5.0, <a href=\"https:\/\/devblogs.microsoft.com\/typescript\/typescripts-migration-to-modules\/\">we moved to modules<\/a>, removed some unnecessary interfaces, and made some correctness improvements.\nFor more details on what&#8217;s changed, see our <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/wiki\/API-Breaking-Changes\">API Breaking Changes<\/a> page.<\/p>\n<h3>Forbidden Implicit Coercions in Relational Operators<\/h3>\n<p>Certain operations in TypeScript will already warn you if you write code which may cause an implicit string-to-number coercion:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>func<\/span><span>(<\/span><span>ns<\/span><span>: <\/span><span>number<\/span><span> | <\/span><span>string<\/span><span>) {<\/span>\r\n<span>  <\/span><span>return<\/span><span> <\/span><span>ns<\/span><span> * <\/span><span>4<\/span><span>; <\/span><span>\/\/ Error, possible implicit coercion<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>In 5.0, this will also be applied to the relational operators <code>&gt;<\/code>, <code>&lt;<\/code>, <code>&lt;=<\/code>, and <code>&gt;=<\/code>:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>func<\/span><span>(<\/span><span>ns<\/span><span>: <\/span><span>number<\/span><span> | <\/span><span>string<\/span><span>) {<\/span>\r\n<span>  <\/span><span>return<\/span><span> <\/span><span>ns<\/span><span> &gt; <\/span><span>4<\/span><span>; <\/span><span>\/\/ Now also an error<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>To allow this if desired, you can explicitly coerce the operand to a <code>number<\/code> using <code>+<\/code>:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>function<\/span><span> <\/span><span>func<\/span><span>(<\/span><span>ns<\/span><span>: <\/span><span>number<\/span><span> | <\/span><span>string<\/span><span>) {<\/span>\r\n<span>  <\/span><span>return<\/span><span> +<\/span><span>ns<\/span><span> &gt; <\/span><span>4<\/span><span>; <\/span><span>\/\/ OK<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>This <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/52048\">correctness improvement<\/a> was contributed courtesy of <a href=\"https:\/\/github.com\/Andarist\">Mateusz Burzy\u0144ski<\/a>.<\/p>\n<h3>Enum Overhaul<\/h3>\n<p>TypeScript has had some long-standing oddities around <code>enum<\/code>s ever since its first release.\nIn 5.0, we&#8217;re cleaning up some of these problems, as well as reducing the concept count needed to understand the various kinds of <code>enum<\/code>s you can declare.<\/p>\n<p>There are two main new errors you might see as part of this.\nThe first is that assigning an out-of-domain literal to an <code>enum<\/code> type will now error as one might expect:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>enum<\/span><span> <\/span><span>SomeEvenDigit<\/span><span> {<\/span>\r\n<span>    <\/span><span>Zero<\/span><span> = <\/span><span>0<\/span><span>,<\/span>\r\n<span>    <\/span><span>Two<\/span><span> = <\/span><span>2<\/span><span>,<\/span>\r\n<span>    <\/span><span>Four<\/span><span> = <\/span><span>4<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ Now correctly an error<\/span>\r\n<span>let<\/span><span> <\/span><span>m<\/span><span>: <\/span><span>SomeEvenDigit<\/span><span> = <\/span><span>1<\/span><span>;<\/span>\r\n<\/code><\/pre>\n<p>The other is that enums with values declared with a mix of numbers and indirect string enum references would incorrectly create an all-number <code>enum<\/code>:<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>enum<\/span><span> <\/span><span>Letters<\/span><span> {<\/span>\r\n<span>    <\/span><span>A<\/span><span> = <\/span><span>&quot;a&quot;<\/span>\r\n<span>}<\/span>\r\n<span>enum<\/span><span> <\/span><span>Numbers<\/span><span> {<\/span>\r\n<span>    <\/span><span>one<\/span><span> = <\/span><span>1<\/span><span>,<\/span>\r\n<span>    <\/span><span>two<\/span><span> = <\/span><span>Letters<\/span><span>.<\/span><span>A<\/span>\r\n<span>}<\/span>\r\n\r\n<span>\/\/ Now correctly an error<\/span>\r\n<span>const<\/span><span> <\/span><span>t<\/span><span>: <\/span><span>number<\/span><span> = <\/span><span>Numbers<\/span><span>.<\/span><span>two<\/span><span>;<\/span>\r\n<\/code><\/pre>\n<p>You can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/50528\">see more details in relevant change<\/a>.<\/p>\n<h3>More Accurate Type-Checking for Parameter Decorators in Constructors Under <code>--experimentalDecorators<\/code><\/h3>\n<p>TypeScript 5.0 makes type-checking more accurate for decorators under <code>--experimentalDecorators<\/code>.\nOne place where this becomes apparent is when using a decorator on a constructor parameter.<\/p>\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><code><span>export<\/span><span> <\/span><span>declare<\/span><span> <\/span><span>const<\/span><span> <\/span><span>inject<\/span><span>:<\/span>\r\n<span>  (<\/span><span>entity<\/span><span>: <\/span><span>any<\/span><span>) <\/span><span>=&gt;<\/span>\r\n<span>    (<\/span><span>target<\/span><span>: <\/span><span>object<\/span><span>, <\/span><span>key<\/span><span>: <\/span><span>string<\/span><span> | <\/span><span>symbol<\/span><span>, <\/span><span>index<\/span><span>?: <\/span><span>number<\/span><span>) <\/span><span>=&gt;<\/span><span> <\/span><span>void<\/span><span>;<\/span>\r\n\r\n<span>export<\/span><span> <\/span><span>class<\/span><span> <\/span><span>Foo<\/span><span> {}<\/span>\r\n\r\n<span>export<\/span><span> <\/span><span>class<\/span><span> <\/span><span>C<\/span><span> {<\/span>\r\n<span>    <\/span><span>constructor<\/span><span>(@<\/span><span>inject<\/span><span>(<\/span><span>Foo<\/span><span>) <\/span><span>private<\/span><span> <\/span><span>x<\/span><span>: <\/span><span>any<\/span><span>) {<\/span>\r\n<span>    }<\/span>\r\n<span>}<\/span>\r\n<\/code><\/pre>\n<p>This call will fail because <code>key<\/code> expects a <code>string | symbol<\/code>, but constructor parameters receive a key of <code>undefined<\/code>.\nThe correct fix is to change the type of <code>key<\/code> within <code>inject<\/code>.\nA reasonable workaround if you&#8217;re using a library that can&#8217;t be upgraded is to wrap <code>inject<\/code> in a more type-safe decorator function, and use a type-assertion on <code>key<\/code>.<\/p>\n<p>For more details, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/52435\">see this issue<\/a>.<\/p>\n<h3>Deprecations and Default Changes<\/h3>\n<p>In TypeScript 5.0, we&#8217;ve deprecated the following settings and setting values:<\/p>\n<ul>\n<li><code>--target: ES3<\/code><\/li>\n<li><code>--out<\/code><\/li>\n<li><code>--noImplicitUseStrict<\/code><\/li>\n<li><code>--keyofStringsOnly<\/code><\/li>\n<li><code>--suppressExcessPropertyErrors<\/code><\/li>\n<li><code>--suppressImplicitAnyIndexErrors<\/code><\/li>\n<li><code>--noStrictGenericChecks<\/code><\/li>\n<li><code>--charset<\/code><\/li>\n<li><code>--importsNotUsedAsValues<\/code><\/li>\n<li><code>--preserveValueImports<\/code><\/li>\n<li><code>prepend<\/code> in project references<\/li>\n<\/ul>\n<p>These configurations will continue to be allowed until TypeScript 5.5, at which point they will be removed entirely, however, you will receive a warning if you are using these settings.\nIn TypeScript 5.0, as well as future releases 5.1, 5.2, 5.3, and 5.4, you can specify <code>&quot;ignoreDeprecations&quot;: &quot;5.0&quot;<\/code> to silence those warnings.\nWe&#8217;ll also shortly be releasing a 4.9 patch to allow specifying <code>ignoreDeprecations<\/code> to allow for smoother upgrades.\nAside from deprecations, we&#8217;ve changed some settings to better improve cross-platform behavior in TypeScript.<\/p>\n<p><code>--newLine<\/code>, which controls the line endings emitted in JavaScript files, used to be inferred based on the current operating system if not specified.\nWe think builds should be as deterministic as possible, and Windows Notepad supports line-feed line endings now, so the new default setting is <code>LF<\/code>.\nThe old OS-specific inference behavior is no longer available.<\/p>\n<p><code>--forceConsistentCasingInFileNames<\/code>, which ensured that all references to the same file name in a project agreed in casing, now defaults to <code>true<\/code>.\nThis can help catch differences issues with code written on case-insensitive file systems.<\/p>\n<p>You can leave feedback and view more information on the <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/51909\">tracking issue for 5.0 deprecations<\/a><\/p>\n<h2>What&#8217;s Next?<\/h2>\n<p>Not to get ahead of ourselves, but TypeScript 5.1 is already in the works, and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/53031\">all our plans are already on GitHub<\/a>.\nIf you&#8217;re eager, we encourage you to <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\">try out our nightly builds of TypeScript<\/a> or the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=ms-vscode.vscode-typescript-next\">JavaScript and TypeScript Nightly extension for VS Code<\/a>!<\/p>\n<p>Of course, we won&#8217;t be hurt if you choose to just enjoy the new stable version of TypeScript.\nWe hope TypeScript 5.0 makes coding faster and more fun for everyone.<\/p>\n<p>Happy Hacking!<\/p>\n<p>&#8211; Daniel Rosenwasser and the TypeScript Team<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re excited to announce the release of TypeScript 5.0! This release brings many new features, while aiming to make TypeScript smaller, simpler, and faster. We&#8217;ve implemented the new decorators standard, added functionality to better support ESM projects in Node and bundlers, provided new ways for library authors to control generic inference, expanded our JSDoc [&hellip;]<\/p>\n","protected":false},"author":381,"featured_media":3781,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3779","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-typescript"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re excited to announce the release of TypeScript 5.0! This release brings many new features, while aiming to make TypeScript smaller, simpler, and faster. We&#8217;ve implemented the new decorators standard, added functionality to better support ESM projects in Node and bundlers, provided new ways for library authors to control generic inference, expanded our JSDoc [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3779","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=3779"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/3779\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/media\/3781"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/media?parent=3779"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=3779"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=3779"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}