{"id":2420,"date":"2020-01-10T13:52:40","date_gmt":"2020-01-10T21:52:40","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=2420"},"modified":"2020-01-22T12:34:27","modified_gmt":"2020-01-22T20:34:27","slug":"announcing-typescript-3-8-beta","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-3-8-beta\/","title":{"rendered":"Announcing TypeScript 3.8 Beta"},"content":{"rendered":"<p>Today we&#8217;re announcing the availability of TypeScript 3.8 Beta! This Beta release contains all the new features you should expect from TypeScript 3.8&#8217;s final release.<\/p>\n<p>To get started using the beta, you can get it <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.TypeScript.MSBuild\" rel=\"nofollow\">through NuGet<\/a>, or through npm with the following command:<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\">npm install typescript@beta<\/pre>\n<\/div>\n<p>You can also get editor support by<\/p>\n<ul>\n<li><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=TypeScriptTeam.TypeScript-38beta\" rel=\"nofollow\">Downloading for Visual Studio 2019\/2017<\/a><\/li>\n<li>Following directions for <a href=\"https:\/\/code.visualstudio.com\/Docs\/languages\/typescript#_using-newer-typescript-versions\" rel=\"nofollow\">Visual Studio Code<\/a> and <a href=\"https:\/\/github.com\/Microsoft\/TypeScript-Sublime-Plugin\/#note-using-different-versions-of-typescript\">Sublime Text<\/a>.<\/li>\n<\/ul>\n<p>TypeScript 3.8 brings a lot of new features, including new or upcoming ECMAScript standards features, new syntax for importing\/exporting only types, and more.<\/p>\n<ul>\n<li><a href=\"#type-only-imports-exports\">Type-Only Imports and Exports<\/a><\/li>\n<li><a href=\"#ecmascript-private-fields\">ECMAScript Private Fields<\/a><\/li>\n<li><a href=\"#export-star-as-namespace-syntax\"><code>export * as ns<\/code> Syntax<\/a><\/li>\n<li><a href=\"#top-level-await\">Top-Level <code>await<\/code><\/a><\/li>\n<li><a href=\"#jsdoc-modifiers\">JSDoc Property Modifiers<\/a><\/li>\n<li><a href=\"#watch-options\"><code>watchOptions<\/code><\/a><\/li>\n<li><a href=\"#assume-direct-dependencies\">&#8220;Fast and Loose&#8221; Incremental Checking<\/a><\/li>\n<\/ul>\n<h2><span id=\"type-only-imports-exports\">Type-Only Imports and Export<\/span><\/h2>\n<p>TypeScript reuses JavaScript&#8217;s import syntax in order to let us reference types. For instance, in the following example, we&#8217;re able to import <code>doThing<\/code> which is a JavaScript value along with <code>Options<\/code> which is purely a TypeScript type.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ .\/foo.ts<\/span>\r\n<span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Options<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">doThing<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">options<\/span>: <span style=\"color: #267F99;\">Options<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ .\/bar.ts<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">doThing<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">Options<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/foo.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">doThingBetter<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">options<\/span>: <span style=\"color: #267F99;\">Options<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ do something twice as good<\/span>\r\n    <span class=\"pl-en\">doThing<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">options<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-en\">doThing<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">options<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>This is convenient because <em>most of the time<\/em> we don&#8217;t have to worry about what&#8217;s being imported &#8211; just that we&#8217;re importing <em>something<\/em>.<\/p>\n<p>Unfortunately, this only worked because of a feature called <em>import elision<\/em>. When TypeScript outputs JavaScript files, it sees that <code>Options<\/code> is only used as a type, and it automatically drops its import. The resulting output looks kind of like this:<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ .\/foo.js<\/span>\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">doThing<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">options<\/span>: <span class=\"pl-v\">Options<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ .\/bar.js<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">doThing<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/foo.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">doThingBetter<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">options<\/span>: <span class=\"pl-v\">Options<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ do something twice as good<\/span>\r\n    <span class=\"pl-en\">doThing<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">options<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-en\">doThing<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">options<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>Again, this behavior is usually great, but it causes some other problems.<\/p>\n<p>First of all, there are some places where it&#8217;s ambiguous whether a value or a type is being exported. For example, in the following example is <code>MyThing<\/code> a value or a type?<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">MyThing<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">export<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">MyThing<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>Limiting ourselves to just this file, there&#8217;s no way to know. Both Babel and TypeScript&#8217;s <code>transpileModule<\/code> API will emit code that doesn&#8217;t work correctly if <code>MyThing<\/code> is only a type, and TypeScript&#8217;s <code>isolatedModules<\/code> flag will warn us that it&#8217;ll be a problem. The real problem here is that there&#8217;s no way to say &#8220;no, no, I really only meant the type &#8211; this should be erased&#8221;, so import elision isn&#8217;t good enough.<\/p>\n<p>The other issue was that TypeScript&#8217;s import elision would get rid of import statements that <em>only<\/em> contained imports used as types. That caused observably different behavior for modules that have side-effects, and so users would have to insert a <em>second<\/em> import statement purely to ensure side-effects.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ This statement will get erased because of import elision.<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">SomeTypeFoo<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">SomeOtherTypeBar<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/module-with-side-effects\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ This statement always sticks around.<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span style=\"color: #a31515;\">\".\/module-with-side-effects\"<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>A concrete place where we saw this coming up was in frameworks like Angular.js (1.x) where <a href=\"https:\/\/docs.angularjs.org\/guide\/services\" rel=\"nofollow\">services<\/a> needed to be registered globally (which is a side-effect), but where those services were only <code>import<\/code>ed for types.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ .\/service.ts<\/span>\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Service<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-en\">register<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"globalServiceId\"<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">Service<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ .\/consumer.ts<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">Service<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/service.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-en\">inject<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"globalServiceId\"<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">service<\/span>: <span style=\"color: #267F99;\">Service<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ do stuff with Service<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>As a result, <code>.\/service.js<\/code> will never get run, and things will break at runtime.<\/p>\n<p>To avoid this class of issues, we realized we needed to give users more fine-grained control over how things were getting imported\/elided.<\/p>\n<p>As a solution in TypeScript 3.8, we&#8217;ve added a new syntax for type-only imports and exports.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span style=\"color: #0000ff;\">type<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">SomeThing<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/some-module.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">type<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">SomeThing<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p><code>import type<\/code> only imports declarations to be used for type annotations and declarations. It <em>always<\/em> gets fully erased, so there&#8217;s no remnant of it at runtime. Similarly, <code>export type<\/code> only provides an export that can be used for type contexts, and is also erased from TypeScript&#8217;s output.<\/p>\n<p>It&#8217;s important to note that classes have a value at runtime and a type at design-time, and the use is very context-sensitive. When using <code>import type<\/code> to import a class, you can&#8217;t do things like extend from it.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span style=\"color: #0000ff;\">type<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">Component<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\"react\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">ButtonProps<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Button<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #267F99;\">Component<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">ButtonProps<\/span><span class=\"pl-kos\">&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/               ~~~~~~~~~<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ error! 'Component' only refers to a type, but is being used as a value here.<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>If you&#8217;ve used Flow before, the syntax is fairly similar. One difference is that we&#8217;ve added a few restrictions to avoid code that might appear ambiguous.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ Is only 'Foo' a type? Or every declaration in the import?<\/span>\r\n<span style=\"color: #148A14;\">\/\/ We just give an error because it's not clear.<\/span>\r\n\r\n<span style=\"color: #0000ff;\">import<\/span> <span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">Foo<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">Bar<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">Baz<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\"some-module\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/     ~~~~~~~~~~~~~~~~~~~~~~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ error! A type-only import can specify a default import or named bindings, but not both.<\/span><\/pre>\n<\/div>\n<p>In conjunction with <code>import type<\/code>, we&#8217;ve also added a new compiler flag to control what happens with imports that won&#8217;t be utilized at runtime: <code>importsNotUsedAsValues<\/code>. At this point the name is tentative, but this flag takes 3 different options:<\/p>\n<ul>\n<li><code>remove<\/code>: this is today&#8217;s behavior of dropping these imports. It&#8217;s going to continue to be the default, and is a non-breaking change.<\/li>\n<li><code>preserve<\/code>: this <em>preserves<\/em> all imports whose values are never used. This can cause imports\/side-effects to be preserved.<\/li>\n<li><code>error<\/code>: this preserves all imports (the same as the <code>preserve<\/code> option), but will error when a value import is only used as a type. This might be useful if you want to ensure no values are being accidentally imported, but still make side-effect imports explicit.<\/li>\n<\/ul>\n<p>For more information about the feature, you can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/35200\">take a look at the pull request<\/a>.<\/p>\n<h3>Type-Only vs Erased<\/h3>\n<p>There is a final note about this feature. In TypeScript 3.8 Beta, only the type meaning of a declaration will be imported by <code>import type<\/code>. That means that you can&#8217;t use values even if they&#8217;re purely used for type positions (like in the <code>extends<\/code> clause of a <code>class<\/code> declared with the <code>declare<\/code> modifier, and the <code>typeof<\/code> type operator).<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> <span style=\"color: #0000ff;\">type<\/span> <span class=\"pl-kos\">{<\/span> <span style=\"color: #267F99;\">Base<\/span> <span class=\"pl-kos\">}<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\"my-library\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">baseConstructor<\/span>: <span style=\"color: #0000ff;\">typeof<\/span> <span style=\"color: #267F99;\">Base<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/                          ~~~~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ error! 'Base' only refers to a type, but is being used as a value here.<\/span>\r\n\r\n<span style=\"color: #0000ff;\">declare<\/span> <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Derived<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #267F99;\">Base<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/                        ~~~~<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ error! 'Base' only refers to a type, but is being used as a value here.<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>We&#8217;re looking at changing this behavior based on recent feedback. Instead of only importing the type side of declarations, we&#8217;re planning on changing the meaning of <code>import type<\/code> to mean &#8220;import whatever this is, but only allow it in type positions.&#8221; In other words, things imported using <code>import type<\/code> can only be used in places where it won&#8217;t affect surrounding JavaScript code.<\/p>\n<p>While this behavior is not in the beta, you can expect it in our upcoming release candidate, and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/36092\/\">keep track of that work on its respective pull request<\/a>.<\/p>\n<h2><span id=\"ecmascript-private-fields\">ECMAScript Private Fields<\/span><\/h2>\n<p>TypeScript 3.8 brings support for ECMAScript&#8217;s private fields, part of the <a href=\"https:\/\/github.com\/tc39\/proposal-class-fields\/\">stage-3 class fields proposal<\/a>. This work was started and driven to completion by our good friends at Bloomberg!<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Person<\/span> <span class=\"pl-kos\">{<\/span>\r\n    #<span class=\"pl-c1\">name<\/span>: <span style=\"color: #0000ff;\">string<\/span>\r\n    \r\n    <span class=\"pl-en\">constructor<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">name<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">name<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">name<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n\r\n    <span class=\"pl-en\">greet<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">`Hello, my name is <span class=\"pl-s1\"><span class=\"pl-kos\">${<\/span><span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">name<\/span><span class=\"pl-kos\">}<\/span><\/span>!`<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">jeremy<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">Person<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"Jeremy Bearimy\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-s1\">jeremy<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">name<\/span>\r\n<span style=\"color: #148A14;\">\/\/     ~~~~~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ Property '#name' is not accessible outside class 'Person'<\/span>\r\n<span style=\"color: #148A14;\">\/\/ because it has a private identifier.<\/span><\/pre>\n<\/div>\n<p>Unlike regular properties (even ones declared with the <code>private<\/code> modifier), private fields have a few rules to keep in mind. Some of them are:<\/p>\n<ul>\n<li>Private fields start with a <code>#<\/code> character. Sometimes we call these <em>private names<\/em>.<\/li>\n<li>Every private field name is uniquely scoped to its containing class.<\/li>\n<li>TypeScript accessibility modifiers like <code>public<\/code> or <code>private<\/code> can&#8217;t be used on private fields.<\/li>\n<li>Private fields can&#8217;t be accessed or even detected outside of the containing class &#8211; even by JS users! Sometimes we call this <em>hard privacy<\/em>.<\/li>\n<\/ul>\n<p>Apart from &#8220;hard&#8221; privacy, another benefit of private fields is that uniqueness we just mentioned. For example, regular property declarations are prone to being overwritten in subclasses.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">foo<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">10<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span class=\"pl-en\">cHelper<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">foo<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">D<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">foo<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">20<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span class=\"pl-en\">dHelper<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">foo<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">instance<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">D<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/ 'this.foo' refers to the same property on each instance.<\/span>\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">instance<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">cHelper<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ prints '20'<\/span>\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">instance<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">dHelper<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ prints '20'<\/span><\/pre>\n<\/div>\n<p>With private fields, you&#8217;ll never have to worry about this, since each field name is unique to the containing class.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    #<span class=\"pl-c1\">foo<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">10<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span class=\"pl-en\">cHelper<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">foo<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">D<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    #<span class=\"pl-c1\">foo<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">20<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span class=\"pl-en\">dHelper<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">foo<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">instance<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">D<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/ 'this.#foo' refers to a different field within each class.<\/span>\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">instance<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">cHelper<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ prints '10'<\/span>\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">instance<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">dHelper<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ prints '20'<\/span><\/pre>\n<\/div>\n<p>Another thing worth noting is that accessing a private field on any other type will result in a <code>TypeError<\/code>!<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">Square<\/span> <span class=\"pl-kos\">{<\/span>\r\n    #<span class=\"pl-c1\">sideLength<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n    \r\n    <span class=\"pl-en\">constructor<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">sideLength<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">sideLength<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">sideLength<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n\r\n    <span class=\"pl-en\">equals<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">other<\/span>: <span style=\"color: #0000ff;\">any<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">return<\/span> <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">sideLength<\/span> <span class=\"pl-c1\">===<\/span> <span class=\"pl-s1\">other<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">sideLength<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">a<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">Square<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #09885A;\">100<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">b<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">sideLength<\/span>: <span style=\"color: #09885A;\">100<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Boom!<\/span>\r\n<span style=\"color: #148A14;\">\/\/ TypeError: attempted to get private field on non-instance<\/span>\r\n<span style=\"color: #148A14;\">\/\/ This fails because 'b' is not an instance of 'Square'.<\/span>\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">a<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">equals<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">b<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>Finally, for any plain <code>.js<\/code> file users, private fields <em>always<\/em> have to be declared before they&#8217;re assigned to.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span class=\"pl-v\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ No declaration for '#foo'<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ :(<\/span>\r\n\r\n    <span class=\"pl-en\">constructor<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">foo<\/span>: <span class=\"pl-s1\">number<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ SyntaxError!<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ '#foo' needs to be declared before writing to it.<\/span>\r\n        <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">foo<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">foo<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>JavaScript has always allowed users to access undeclared properties, whereas TypeScript has always required declarations for class properties. With private fields, declarations are always needed regardless of whether we&#8217;re working in <code>.js<\/code> or <code>.ts<\/code> files.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span class=\"pl-v\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/** @type {number} *\/<\/span>\r\n    #<span class=\"pl-c1\">foo<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span class=\"pl-en\">constructor<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">foo<\/span>: <span class=\"pl-s1\">number<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ This works.<\/span>\r\n        <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">foo<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">foo<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>For more information about the implementation, you can <a href=\"https:\/\/github.com\/Microsoft\/TypeScript\/pull\/30829\">check out the original pull request<\/a><\/p>\n<h3>Which should I use?<\/h3>\n<p>We&#8217;ve already received many questions on which type of privates you should use as a TypeScript user: most commonly, &#8220;should I use the <code>private<\/code> keyword, or ECMAScript&#8217;s hash\/pound (<code>#<\/code>) private fields?&#8221;<\/p>\n<p>Like all good questions, the answer is not good: it depends!<\/p>\n<p>When it comes to properties, TypeScript&#8217;s <code>private<\/code> modifiers are fully erased &#8211; that means that while the data will be there, nothing is encoded in your JavaScript output about how the property was declared. At runtime, it acts entirely like a normal property. That means that when using the <code>private<\/code> keyword, privacy is only enforced at compile-time\/design-time, and for JavaScript consumers, it&#8217;s entirely intent-based.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">private<\/span> <span class=\"pl-c1\">foo<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">10<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ This is an error at compile time,<\/span>\r\n<span style=\"color: #148A14;\">\/\/ but when TypeScript outputs .js files,<\/span>\r\n<span style=\"color: #148A14;\">\/\/ it'll run fine and print '10'.<\/span>\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">C<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">foo<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>    <span style=\"color: #148A14;\">\/\/ prints '10'<\/span>\r\n<span style=\"color: #148A14;\">\/\/                  ~~~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ error! Property 'foo' is private and only accessible within class 'C'.<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ TypeScript allows this at compile-time<\/span>\r\n<span style=\"color: #148A14;\">\/\/ as a \"work-around\" to avoid the error.<\/span>\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">C<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #a31515;\">\"foo\"<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ prints '10'<\/span><\/pre>\n<\/div>\n<p>The upside is that this sort of &#8220;soft privacy&#8221; can help your consumers temporarily work around not having access to some API, and works in any runtime.<\/p>\n<p>On the other hand, ECMAScript&#8217;s <code>#<\/code> privates are completely inaccessible outside of the class.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span>\r\n    #<span class=\"pl-c1\">foo<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">10<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">C<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">.<\/span>#<span class=\"pl-c1\">foo<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ SyntaxError<\/span>\r\n<span style=\"color: #148A14;\">\/\/                  ~~~~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ TypeScript reports an error *and*<\/span>\r\n<span style=\"color: #148A14;\">\/\/ this won't work at runtime!<\/span>\r\n\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">new<\/span> <span style=\"color: #267F99;\">C<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #a31515;\">\"#foo\"<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ prints undefined<\/span>\r\n<span style=\"color: #148A14;\">\/\/          ~~~~~~~~~~~~~~~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ TypeScript reports an error under 'noImplicitAny',<\/span>\r\n<span style=\"color: #148A14;\">\/\/ and this prints 'undefined'.<\/span><\/pre>\n<\/div>\n<p>This hard privacy is really useful for strictly ensuring that nobody can take use of any of your internals. If you&#8217;re a library author, removing or renaming a private field should never cause a breaking change.<\/p>\n<p>As we mentioned, another benefit is that subclassing can be easier with ECMAScript&#8217;s <code>#<\/code> privates because they <em>really<\/em> are private. When using ECMAScript <code>#<\/code> private fields, no subclass ever has to worry about collisions in field naming. When it comes to TypeScript&#8217;s <code>private<\/code> property declarations, users still have to be careful not to trample over properties declared in superclasses.<\/p>\n<p>Finally, something to consider is where you intend for your code to run. TypeScript currently can&#8217;t support this feature unless targeting ECMAScript 2015 (ES6) targets or higher. This is because our downleveled implementation uses <code>WeakMap<\/code>s to enforce privacy, and <code>WeakMap<\/code>s can&#8217;t be polyfilled in a way that doesn&#8217;t cause memory leaks. In contrast, TypeScript&#8217;s <code>private<\/code>-declared properties work with all targets &#8211; even ECMAScript 3!<\/p>\n<h3>Kudos!<\/h3>\n<p>It&#8217;s worth reiterating how much work went into this feature from our contributors at Bloomberg. They were diligent in taking the time to learn to contribute features to the compiler\/language service, and paid close attention to the ECMAScript specification to test that the feature was implemented in compliant manner. They even improved another 3rd party project, <a href=\"https:\/\/github.com\/cla-assistant\/cla-assistant\/pull\/410\">CLA Assistant<\/a>, which made contributing to TypeScript even easier.<\/p>\n<p>We&#8217;d like to extend a special thanks to:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/joeywatts\">Joey Watts<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/mheiber\">Max Heiber<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/robpalme\">Rob Palmer<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Neuroboy23\">Michael Gunter<\/a><\/li>\n<li>Ravi Amin<\/li>\n<li><a href=\"https:\/\/github.com\/jbhoosreddy\">Jaideep Bhoosreddy<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/molisani\">Michael Molisani<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/tim-mc\">Tim McClure<\/a><\/li>\n<\/ul>\n<h2><span id=\"export-star-as-namespace-syntax\"><code>export * as ns<\/code> Syntax<\/span><\/h2>\n<p>It&#8217;s often common to have a single entry-point that exposes all the members of another module as a single member.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">import<\/span> * <span style=\"color: #0000ff;\">as<\/span> <span class=\"pl-s1\">utilities<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/utilities.js\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">export<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-s1\">utilities<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>This is so common that ECMAScript 2020 recently added a new syntax to support this pattern!<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">export<\/span> * <span style=\"color: #0000ff;\">as<\/span> <span class=\"pl-s1\">utilities<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/utilities.js\"<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>This is a nice quality-of-life improvement to JavaScript, and TypeScript 3.8 implements this syntax. When your module target is earlier than <code>es2020<\/code>, TypeScript will output something along the lines of the first code snippet.<\/p>\n<p>Special thanks to community member <a href=\"https:\/\/github.com\/Kingwl\">Wenlu Wang (Kingwl)<\/a> who implemented this feature! For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/34903\">check out the original pull request<\/a>.<\/p>\n<h2><span id=\"top-level-await\">Top-Level <code>await<\/code><\/span><\/h2>\n<p>Most modern environments that provide I\/O in JavaScript (like HTTP requests) is asynchronous, and many modern APIs return <code>Promise<\/code>s. While this has a lot of benefits in making operations non-blocking, it makes certain things like loading files or external content surprisingly tedious.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span class=\"pl-en\">fetch<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"...\"<\/span><span class=\"pl-kos\">)<\/span>\r\n    <span class=\"pl-kos\">.<\/span><span class=\"pl-en\">then<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">response<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-s1\">response<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">text<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span>\r\n    <span class=\"pl-kos\">.<\/span><span class=\"pl-en\">then<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">greeting<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">greeting<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>To avoid <code>.then<\/code> chains with <code>Promise<\/code>s, JavaScript users often introduced an <code>async<\/code> function in order to use <code>await<\/code>, and then immediately called the function after defining it.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">async<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">main<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">response<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">await<\/span> <span class=\"pl-en\">fetch<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"...\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">greeting<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">await<\/span> <span class=\"pl-s1\">response<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">text<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">greeting<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span class=\"pl-en\">main<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span>\r\n    <span class=\"pl-kos\">.<\/span><span class=\"pl-en\">catch<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">e<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">error<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">e<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><\/pre>\n<\/div>\n<p>To avoid introducing an <code>async<\/code> function, we can use a handy upcoming ECMAScript feature called &#8220;top-level <code>await<\/code>&#8220;.<\/p>\n<p>Previously in JavaScript (along with most other languages with a similar feature), <code>await<\/code> was only allowed within the body of an <code>async<\/code> function. However, with top-level <code>await<\/code>, we can use <code>await<\/code> at the top level of a module.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">response<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">await<\/span> <span class=\"pl-en\">fetch<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"...\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">greeting<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #0000ff;\">await<\/span> <span class=\"pl-s1\">response<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">text<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">greeting<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Make sure we're a module<\/span>\r\n<span style=\"color: #0000ff;\">export<\/span> <span class=\"pl-kos\">{<\/span><span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>Note there&#8217;s a subtlety: top-level <code>await<\/code> only works at the top level of a <em>module<\/em>, and files are only considered modules when TypeScript finds an <code>import<\/code> or an <code>export<\/code>. In some basic cases, you might need to write out <code>export {}<\/code> as some boilerplate to make sure of this.<\/p>\n<p>Top level <code>await<\/code> may not work in all environments where you might expect at this point. Currently, you can only use top level <code>await<\/code> when the <code>target<\/code> compiler option is <code>es2017<\/code> or above, and <code>module<\/code> is <code>esnext<\/code> or <code>system<\/code>. Support within several environments and bundlers may be limited or may require enabling experimental support.<\/p>\n<p>For more information on our implementation, you can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/35813\">check out the original pull request<\/a>.<\/p>\n<h2><span id=\"es2020-for-target-and-module\"><code>es2020<\/code> for <code>target<\/code> and <code>module<\/code><\/span><\/h2>\n<p>Thanks to <a href=\"https:\/\/github.com\/saschanaz\">Kagami Sascha Rosylight (saschanaz)<\/a>, TypeScript 3.8 supports <code>es2020<\/code> as an option for <code>module<\/code> and <code>target<\/code>. This will preserve newer ECMAScript 2020 features like optional chaining, nullish coalescing, <code>export * as ns<\/code>, and dynamic <code>import(...)<\/code> syntax. It also means <code>bigint<\/code> literals now have a stable <code>target<\/code> below <code>esnext<\/code>.<\/p>\n<h2><span id=\"jsdoc-modifiers\">JSDoc Property Modifiers<\/span><\/h2>\n<p>TypeScript 3.8 supports JavaScript files by turning on the <code>allowJs<\/code> flag, and also supports <em>type-checking<\/em> those JavaScript files via the <code>checkJs<\/code> option or by adding a <code>\/\/ @ts-check<\/code> comment to the top of your <code>.js<\/code> files.<\/p>\n<p>Because JavaScript files don&#8217;t have dedicated syntax for type-checking, TypeScript leverages JSDoc. TypeScript 3.8 understands a few new JSDoc tags for properties.<\/p>\n<p>First are the accessibility modifiers: <code>@public<\/code>, <code>@private<\/code>, and <code>@protected<\/code>. These tags work exactly like <code>public<\/code>, <code>private<\/code>, and <code>protected<\/code> respectively work in TypeScript.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ @ts-check<\/span>\r\n\r\n<span style=\"color: #0000ff;\">class<\/span> <span class=\"pl-v\">Foo<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">constructor<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/** @private *\/<\/span>\r\n        <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">stuff<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">100<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n\r\n    <span class=\"pl-en\">printStuff<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-smi\">console<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">log<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">stuff<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">new<\/span> <span class=\"pl-v\">Foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">stuff<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/        ~~~~~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ error! Property 'stuff' is private and only accessible within class 'Foo'.<\/span><\/pre>\n<\/div>\n<ul>\n<li><code>@public<\/code> is always implied and can be left off, but means that a property can be reached from anywhere.<\/li>\n<li><code>@private<\/code> means that a property can only be used within the containing class.<\/li>\n<li><code>@protected<\/code> means that a property can only be used within the containing class, and all derived subclasses, but not on dissimilar instances of the containing class.<\/li>\n<\/ul>\n<p>Next, we&#8217;ve also added the <code>@readonly<\/code> modifier to ensure that a property is only ever written to during initialization.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ @ts-check<\/span>\r\n\r\n<span style=\"color: #0000ff;\">class<\/span> <span class=\"pl-v\">Foo<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">constructor<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/** @readonly *\/<\/span>\r\n        <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">stuff<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">100<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n\r\n    <span class=\"pl-en\">writeToStuff<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #0000ff;\">this<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">stuff<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">200<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span style=\"color: #148A14;\">\/\/   ~~~~~<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ Cannot assign to 'stuff' because it is a read-only property.<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">new<\/span> <span class=\"pl-v\">Foo<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">stuff<\/span><span class=\"pl-c1\">++<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/        ~~~~~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ Cannot assign to 'stuff' because it is a read-only property.<\/span><\/pre>\n<\/div>\n<h2><span id=\"watch-options\"><code>watchOptions<\/code><\/span><\/h2>\n<p>TypeScript has strived to provide reliable file-watching capabilities in <code>--watch<\/code> mode and in editors for years. While it&#8217;s worked well for the most part, it turns out that file-watching in Node.js is hard, and its drawbacks can be reflected in our logic. The built-in APIs in Node.js are either CPU\/energy-intensive and inaccurate (<a href=\"https:\/\/nodejs.org\/api\/fs.html#fs_fs_watchfile_filename_options_listener\" rel=\"nofollow\"><code>fs.watchFile<\/code><\/a>) or they&#8217;re wildly inconsistent across platforms (<a href=\"https:\/\/nodejs.org\/api\/fs.html#fs_fs_watch_filename_options_listener\" rel=\"nofollow\"><code>fs.watch<\/code><\/a>). Additionally, it&#8217;s practically impossible to determine which API will work better because it depends not only on the platform, but the file system on which a file resides.<\/p>\n<p>This has been a struggle, because TypeScript needs to run on more platforms than just Node.js, and also strives to avoid dependencies to be entirely self-contained. This especially applies to dependencies on native Node.js modules.<\/p>\n<p>Because every project might work better under different strategies, TypeScript 3.8 introduces a new <code>watchOptions<\/code> field in <code>tsconfig.json<\/code> and <code>jsconfig.json<\/code> which allows users to tell the compiler\/language service which watching strategies should be used to keep track of files and directories.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ Some typical compiler options<\/span>\r\n    <span style=\"color: #a31515;\">\"compilerOptions\"<\/span>: <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #a31515;\">\"target\"<\/span>: <span style=\"color: #a31515;\">\"es2020\"<\/span><span class=\"pl-kos\">,<\/span>\r\n        <span style=\"color: #a31515;\">\"moduleResolution\"<\/span>: <span style=\"color: #a31515;\">\"node\"<\/span><span class=\"pl-kos\">,<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ ...<\/span>\r\n    <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">,<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ NEW: Options for file\/directory watching<\/span>\r\n    <span style=\"color: #a31515;\">\"watchOptions\"<\/span>: <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ Use native file system events for files and directories<\/span>\r\n        <span style=\"color: #a31515;\">\"watchFile\"<\/span>: <span style=\"color: #a31515;\">\"useFsEvents\"<\/span><span class=\"pl-kos\">,<\/span>\r\n        <span style=\"color: #a31515;\">\"watchDirectory\"<\/span>: <span style=\"color: #a31515;\">\"useFsEvents\"<\/span><span class=\"pl-kos\">,<\/span>\r\n\r\n        <span style=\"color: #148A14;\">\/\/ Poll files for updates more frequently<\/span>\r\n        <span style=\"color: #148A14;\">\/\/ when they're updated a lot.<\/span>\r\n        <span style=\"color: #a31515;\">\"fallbackPolling\"<\/span>: <span style=\"color: #a31515;\">\"dynamicPriority\"<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p><code>watchOptions<\/code> contains 4 new options that can be configured:<\/p>\n<ul>\n<li><code>watchFile<\/code>: the strategy for how individual files are watched. This can be set to\n<ul>\n<li><code>fixedPollingInterval<\/code>: Check every file for changes several times a second at a fixed interval.<\/li>\n<li><code>priorityPollingInterval<\/code>: Check every file for changes several times a second, but use heuristics to check certain types of files less frequently than others.<\/li>\n<li><code>dynamicPriorityPolling<\/code>: Use a dynamic queue where less-frequently modified files will be checked less often.<\/li>\n<li><code>useFsEvents<\/code> (the default): Attempt to use the operating system\/file system&#8217;s native events for file changes.<\/li>\n<li><code>useFsEventsOnParentDirectory<\/code>: Attempt to use the operating system\/file system&#8217;s native events to listen for changes on a file&#8217;s containing directories. This can use fewer file watchers, but might be less accurate.<\/li>\n<\/ul>\n<\/li>\n<li><code>watchDirectory<\/code>: the strategy for how entire directory trees are watched under systems that lack recursive file-watching functionality. This can be set to:\n<ul>\n<li><code>fixedPollingInterval<\/code>: Check every directory for changes several times a second at a fixed interval.<\/li>\n<li><code>dynamicPriorityPolling<\/code>: Use a dynamic queue where less-frequently modified directories will be checked less often.<\/li>\n<li><code>useFsEvents<\/code> (the default): Attempt to use the operating system\/file system&#8217;s native events for directory changes.<\/li>\n<\/ul>\n<\/li>\n<li><code>fallbackPolling<\/code>: when using file system events, this option specifies the polling strategy that gets used when the system runs out of native file watchers and\/or doesn&#8217;t support native file watchers. This can be set to\n<ul>\n<li><code>fixedPollingInterval<\/code>: <em>(See above.)<\/em><\/li>\n<li><code>priorityPollingInterval<\/code>: <em>(See above.)<\/em><\/li>\n<li><code>dynamicPriorityPolling<\/code>: <em>(See above.)<\/em><\/li>\n<\/ul>\n<\/li>\n<li><code>synchronousWatchDirectory<\/code>: Disable deferred watching on directories. Deferred watching is useful when lots of file changes might occur at once (e.g. a change in <code>node_modules<\/code> from running <code>npm install<\/code>), but you might want to disable it with this flag for some less-common setups.<\/li>\n<\/ul>\n<p>For more information on <code>watchOptions<\/code>, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/35615\">head over to GitHub to see the pull request<\/a>.<\/p>\n<h2><span id=\"assume-direct-dependencies\">&#8220;Fast and Loose&#8221; Incremental Checking<\/span><\/h2>\n<p>TypeScript&#8217;s <code>--watch<\/code> mode and <code>--incremental<\/code> mode can help tighten the feedback loop for projects. Turning on <code>--incremental<\/code> mode makes TypeScript keep track of which files can affect others, and on top of doing that, <code>--watch<\/code> mode keeps the compiler process open and reuses as much information in memory as possible.<\/p>\n<p>However, for much larger projects, even the dramatic gains in speed that these options afford us isn&#8217;t enough. For example, the Visual Studio Code team had built their own build tool around TypeScript called <code>gulp-tsb<\/code> which would be less accurate in assessing which files needed to be rechecked\/rebuilt in its watch mode, and as a result, could provide drastically low build times.<\/p>\n<p>Sacrificing accuracy for build speed, for better or worse, is a tradeoff many are willing to make in the TypeScript\/JavaScript world. Lots of users prioritize tightening their iteration time over addressing the errors up-front. As an example, it&#8217;s fairly common to build code regardless of the results of type-checking or linting.<\/p>\n<p>TypeScript 3.8 introduces a new compiler option called <code>assumeChangesOnlyAffectDirectDependencies<\/code>. When this option is enabled, TypeScript will avoid rechecking\/rebuilding all truly possibly-affected files, and only recheck\/rebuild files that have changed as well as files that directly import them.<\/p>\n<p>For example, consider a file <code>fileD.ts<\/code> that imports <code>fileC.ts<\/code> that imports <code>fileB.ts<\/code> that imports <code>fileA.ts<\/code> as follows:<\/p>\n<pre><code>fileA.ts &lt;- fileB.ts &lt;- fileC.ts &lt;- fileD.ts\r\n<\/code><\/pre>\n<p>In <code>--watch<\/code> mode, a change in <code>fileA.ts<\/code> would typically mean that TypeScript would need to at least re-check <code>fileB.ts<\/code>, <code>fileC.ts<\/code>, and <code>fileD.ts<\/code>. Under <code>assumeChangesOnlyAffectDirectDependencies<\/code>, a change in <code>fileA.ts<\/code> means that only <code>fileA.ts<\/code> and <code>fileB.ts<\/code> need to be re-checked.<\/p>\n<p>In a codebase like Visual Studio Code, this reduced rebuild times for changes in certain files from about 14 seconds to about 1 second. While we don&#8217;t necessarily recommend this option for all codebases, you might be interested if you have an extremely large codebase and are willing to defer full project errors until later (e.g. a dedicated build via a <code>tsconfig.fullbuild.json<\/code> or in CI).<\/p>\n<p>For more details, you can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/35711\">see the original pull request<\/a>.<\/p>\n<h2>Breaking Changes<\/h2>\n<p>TypeScript 3.8 contains a few minor breaking changes that should be noted.<\/p>\n<h3>Stricter Assignability Checks to Unions with Index Signatures<\/h3>\n<p>Previously, excess properties were unchecked when assigning to unions where <em>any<\/em> type had an index signature &#8211; even if that excess property could <em>never<\/em> satisfy that index signature. In TypeScript 3.8, the type-checker is stricter, and only &#8220;exempts&#8221; properties from excess property checks if that property could plausibly satisfy an index signature.<\/p>\n<div class=\"highlight highlight-source-ts\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">obj1<\/span>: <span class=\"pl-kos\">{<\/span> <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">x<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">}<\/span> | <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">a<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-s1\">obj1<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">a<\/span>: <span style=\"color: #09885A;\">5<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-c1\">c<\/span>: <span style=\"color: #a31515;\">'abc'<\/span> <span class=\"pl-kos\">}<\/span>\r\n<span style=\"color: #148A14;\">\/\/             ~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ Error!<\/span>\r\n<span style=\"color: #148A14;\">\/\/ The type '{ [x: string]: number }' no longer exempts 'c'<\/span>\r\n<span style=\"color: #148A14;\">\/\/ from excess property checks on '{ a: number }'.<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">obj2<\/span>: <span class=\"pl-kos\">{<\/span> <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">x<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">}<\/span> | <span class=\"pl-kos\">{<\/span> <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">x<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">number<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-s1\">obj2<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">a<\/span>: <span style=\"color: #a31515;\">'abc'<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/       ~<\/span>\r\n<span style=\"color: #148A14;\">\/\/ Error!<\/span>\r\n<span style=\"color: #148A14;\">\/\/ The types '{ [x: string]: number }' and '{ [x: number]: number }' no longer exempts 'a'<\/span>\r\n<span style=\"color: #148A14;\">\/\/ from excess property checks against '{ [x: number]: number }',<\/span>\r\n<span style=\"color: #148A14;\">\/\/ and it *is* sort of an excess property because 'a' isn't a numeric property name.<\/span>\r\n<span style=\"color: #148A14;\">\/\/ This one is more subtle.<\/span><\/pre>\n<\/div>\n<h3><code>object<\/code> in JSDoc is No Longer <code>any<\/code> Under <code>noImplicitAny<\/code><\/h3>\n<p>Historically, TypeScript&#8217;s support for checking JavaScript has been lax in certain ways in order to provide an approachable experience.<\/p>\n<p>For example, users often used <code>Object<\/code> in JSDoc to mean, &#8220;some object, I dunno what&#8221;, we&#8217;ve treated it as <code>any<\/code>.<\/p>\n<div class=\"highlight highlight-source-js\">\n<pre class=\"lang:default decode:true\" style=\"background-color: #f0f0f0;padding: 10px;border-radius: 10px;\"><span style=\"color: #148A14;\">\/\/ @ts-check<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/**<\/span>\r\n<span style=\"color: #148A14;\"> * @param thing {Object} some object, i dunno what<\/span>\r\n<span style=\"color: #148A14;\"> *\/<\/span>\r\n<span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">doSomething<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">thing<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">x<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">thing<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">x<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">y<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">thing<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">y<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-s1\">thing<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>This is because treating it as TypeScript&#8217;s <code>Object<\/code> type would end up in code reporting uninteresting errors, since the <code>Object<\/code> type is an extremely vague type with few capabilities other than methods like <code>toString<\/code> and <code>valueOf<\/code>.<\/p>\n<p>However, TypeScript <em>does<\/em> have a more useful type named <code>object<\/code> (notice that lowercase <code>o<\/code>). The <code>object<\/code> type is more restrictive than <code>Object<\/code>, in that it rejects all primitive types like <code>string<\/code>, <code>boolean<\/code>, and <code>number<\/code>. Unfortunately, both <code>Object<\/code> and <code>object<\/code> were treated as <code>any<\/code> in JSDoc.<\/p>\n<p>Because <code>object<\/code> can come in handy and is used significantly less than <code>Object<\/code> in JSDoc, we&#8217;ve removed the special-case behavior in JavaScript files when using <code>noImplicitAny<\/code> so that in JSDoc, the <code>object<\/code> type really refers to the non-primitive <code>object<\/code> type.<\/p>\n<h2>What&#8217;s Next?<\/h2>\n<p>Now that the beta is out, our team has been focusing largely on bug fixes and polish for what will eventually become TypeScript 3.8. As you can see on <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/34898\">our current Iteration Plan<\/a>, we&#8217;ll have one release candidate (a pre-release) in a couple of weeks, followed by a full release around mid-February. As editor features we&#8217;ve developed become more mature, we&#8217;ll also show off functionality like Call Hierarchy and the &#8220;convert to template string&#8221; refactoring.<\/p>\n<p>If you&#8217;re able to give our beta a try, we would highly appreciate your feedback! So download it today, and happy hacking!<\/p>\n<p>&#8211; Daniel Rosenwasser and the TypeScript Team<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re announcing the availability of TypeScript 3.8 Beta! This Beta release contains all the new features you should expect from TypeScript 3.8&#8217;s final release. To get started using the beta, you can get it through NuGet, or through npm with the following command: npm install typescript@beta You can also get editor support by Downloading [&hellip;]<\/p>\n","protected":false},"author":381,"featured_media":1797,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2420","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-typescript"],"acf":[],"blog_post_summary":"<p>Today we&#8217;re announcing the availability of TypeScript 3.8 Beta! This Beta release contains all the new features you should expect from TypeScript 3.8&#8217;s final release. To get started using the beta, you can get it through NuGet, or through npm with the following command: npm install typescript@beta You can also get editor support by Downloading [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/2420","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=2420"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/2420\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/media\/1797"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/media?parent=2420"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=2420"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=2420"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}