{"id":2984,"date":"2021-05-26T09:37:31","date_gmt":"2021-05-26T17:37:31","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=2984"},"modified":"2026-02-08T17:14:55","modified_gmt":"2026-02-09T01:14:55","slug":"announcing-typescript-4-3","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-3\/","title":{"rendered":"Announcing TypeScript 4.3"},"content":{"rendered":"<p>Today we&#8217;re excited to announce the availability of TypeScript 4.3!<\/p>\n<p>If you&#8217;re not yet familiar with TypeScript, it&#8217;s a language that builds on JavaScript by adding syntax for static types.\nTools like the TypeScript compiler can just erase TypeScript syntax, leaving you with clean readable JavaScript that works anywhere.\nSo what&#8217;s that syntax adding if it just gets erased away?\nWell, when you add types throughout your code, you&#8217;re making your intentions explicit, and TypeScript can <em>type-check<\/em> your code to catch mistakes like typos, logic errors, and more!\nTypeScript also uses those types to power editor tooling, giving you nice features like accurate code-completion, rename, and go-to-definition!\nYou can learn more <a href=\"https:\/\/www.typescriptlang.org\/\">on the TypeScript website<\/a>.<\/p>\n<p>To start using TypeScript 4.3, 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=\"prettyprint language-sh\" style=\"padding: 10px; border-radius: 10px;\"><code>npm install typescript\r\n<\/code><\/pre>\n<p>You can also get editor support by<\/p>\n<ul>\n<li><a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=TypeScriptTeam.TypeScript-43\">Downloading for Visual Studio 2019\/2017<\/a><\/li>\n<li><a href=\"http:\/\/code.visualstudio.com\/insiders\">Installing the Insiders Version of Visual Studio Code<\/a> or following directions to <a href=\"https:\/\/code.visualstudio.com\/docs\/typescript\/typescript-compiling#_using-newer-typescript-versions\">use a newer version of TypeScript<\/a><\/li>\n<li><a href=\"https:\/\/packagecontrol.io\/packages\/TypeScript\">Using Package Control for Sublime Text 3<\/a>.<\/li>\n<\/ul>\n<p>Let&#8217;s dive in to what TypeScript 4.3 brings!<\/p>\n<ul>\n<li><a href=\"#separate-write-types\">Separate Write Types on Properties<\/a><\/li>\n<li><a href=\"#override\"><code>override<\/code> and the <code>--noImplicitOverride<\/code> Flag<\/a><\/li>\n<li><a href=\"#template-string-improvements\">Template String Type Improvements<\/a><\/li>\n<li><a href=\"#private-elements\">ECMAScript <code>#private<\/code> Class Elements<\/a><\/li>\n<li><a href=\"#constructor-parameters\"><code>ConstructorParameters<\/code> Works on Abstract Classes<\/a><\/li>\n<li><a href=\"#contextual-narrowing\">Contextual Narrowing for Generics<\/a><\/li>\n<li><a href=\"#truthy-promise-checks\">Always-Truthy Promise Checks<\/a><\/li>\n<li><a href=\"#static-index-signatures\"><code>static<\/code> Index Signatures<\/a><\/li>\n<li><a href=\"#tsbuildinfo-is-smol\"><code>.tsbuildinfo<\/code> Size Improvements<\/a><\/li>\n<li><a href=\"#lazier-incremental\">Lazier Calculations in <code>--incremental<\/code> and <code>--watch<\/code> Compilations<\/a><\/li>\n<li><a href=\"#import-statement-completions\">Import Statement Completions<\/a><\/li>\n<li><a href=\"#jsdoc-link-tags\">Editor Support for <code>@link<\/code> Tags<\/a><\/li>\n<li><a href=\"#go-to-def-non-js\">Go-to-Definition on Non-JavaScript File Paths<\/a><\/li>\n<li><a href=\"#breaking-changes\">Breaking Changes<\/a><\/li>\n<li><a href=\"#whats-next\">What&#8217;s Next?<\/a><\/li>\n<\/ul>\n<h2 id=\"separate-write-types-on-properties\"><a name=\"separate-write-types\"><\/a> Separate Write Types on Properties<\/h2>\n<p>In JavaScript, it&#8217;s pretty common for APIs to convert values that are passed in before storing them.\nThis often happens with getters and setters too.\nFor example, let&#8217;s imagine we&#8217;ve got a class with a setter that always converts a value into a <code>number<\/code> before saving it in a private field.<\/p>\n<pre class=\"prettyprint language-javascript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Thing {\r\n    #size = 0;\r\n\r\n    get size() {\r\n        return this.#size;\r\n    }\r\n    set size(value) {\r\n        let num = Number(value);\r\n\r\n        \/\/ Don't allow NaN and stuff.\r\n        if (!Number.isFinite(num)) {\r\n            this.#size = 0;\r\n            return;\r\n        }\r\n\r\n        this.#size = num;\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>How would we type this JavaScript code in TypeScript?\nWell, technically we don&#8217;t have to do anything special here &#8211; TypeScript can look at this with no explicit types and can figure out that <code>size<\/code> is a number.<\/p>\n<p>The problem is that <code>size<\/code> allows you to assign more than just <code>number<\/code>s to it.\nWe could get around this by saying that <code>size<\/code> has the type <code>unknown<\/code> or <code>any<\/code> like in this snippet:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Thing {\r\n    \/\/ ...\r\n    get size(): unknown {\r\n        return this.#size;\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>But that&#8217;s no good &#8211; <code>unknown<\/code> forces people reading <code>size<\/code> to do a type assertion, and <code>any<\/code> won&#8217;t catch any mistakes.\nIf we really want to model APIs that convert values, previous versions of TypeScript forced us to pick between being precise (which makes reading values easier, and writing harder) and being permissive (which makes writing values easier, and reading harder).<\/p>\n<p>That&#8217;s why TypeScript 4.3 allows you to specify types for reading and writing to properties.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Thing {\r\n    #size = 0;\r\n\r\n    get size(): number {\r\n        return this.#size;\r\n    }\r\n\r\n    set size(value: string | number | boolean) {\r\n        let num = Number(value);\r\n\r\n        \/\/ Don't allow NaN and stuff.\r\n        if (!Number.isFinite(num)) {\r\n            this.#size = 0;\r\n            return;\r\n        }\r\n\r\n        this.#size = num;\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>In the above example, our <code>set<\/code> accessor takes a broader set of types (<code>string<\/code>s, <code>boolean<\/code>s, and <code>number<\/code>s), but our <code>get<\/code> accessor always guarantees it will be a <code>number<\/code>.\nNow we can finally assign other types to these properties with no errors!<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>let thing = new Thing();\r\n\r\n\/\/ Assigning other types to `thing.size` works!\r\nthing.size = \"hello\";\r\nthing.size = true;\r\nthing.size = 42;\r\n\r\n\/\/ Reading `thing.size` always produces a number!\r\nlet mySize: number = thing.size;\r\n<\/code><\/pre>\n<p>When considering how two properties with the same name relate to each other, TypeScript will only use the &#8220;reading&#8221; type (e.g. the type on the <code>get<\/code> accessor above).\n&#8220;Writing&#8221; types are only considered when directly writing to a property.<\/p>\n<p>Keep in mind, this isn&#8217;t a pattern that&#8217;s limited to classes.\nYou can write getters and setters with different types in object literals.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>function makeThing(): Thing {\r\n    let size = 0;\r\n    return {\r\n        get size(): number {\r\n            return size;\r\n        },\r\n        set size(value: string | number | boolean) {\r\n            let num = Number(value);\r\n\r\n            \/\/ Don't allow NaN and stuff.\r\n            if (!Number.isFinite(num)) {\r\n                size = 0;\r\n                return;\r\n            }\r\n\r\n            size = num;\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>In fact, we&#8217;ve added syntax to interfaces\/object types to support different reading\/writing types on properties.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>\/\/ Now valid!\r\ninterface Thing {\r\n    get size(): number\r\n    set size(value: number | string | boolean);\r\n}\r\n<\/code><\/pre>\n<p>One limitation of using different types for reading and writing properties is that the type for reading a property has to be assignable to the type that you&#8217;re writing.\nIn other words, the getter type has to be assignable to the setter.\nThis ensures some level of consistency, so that a property is always assignable to itself.<\/p>\n<p>For more information on this feature, take a look at <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/42425\">the implementing pull request<\/a>.<\/p>\n<h2 id=\"override-and-the---noimplicitoverride-flag\"><a name=\"override\"><\/a> <code>override<\/code> and the <code>--noImplicitOverride<\/code> Flag<\/h2>\n<p>When extending classes in JavaScript, the language makes it super easy (pun intended) to override methods &#8211; but unfortunately, there are some mistakes that you can run into.<\/p>\n<p>One big one is missing renames.\nFor example, take the following classes:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class SomeComponent {\r\n    show() {\r\n        \/\/ ...\r\n    }\r\n    hide() {\r\n        \/\/ ...\r\n    }\r\n}\r\n\r\nclass SpecializedComponent extends SomeComponent {\r\n    show() {\r\n        \/\/ ...\r\n    }\r\n    hide() {\r\n        \/\/ ...\r\n    }\r\n}\r\n<\/code><\/pre>\n<p><code>SpecializedComponent<\/code> subclasses <code>SomeComponent<\/code>, and overrides the <code>show<\/code> and <code>hide<\/code> methods.\nWhat happens if someone decides to rip out <code>show<\/code> and <code>hide<\/code> and replace them with a single method?<\/p>\n<pre class=\"prettyprint language-diff\" style=\"padding: 10px; border-radius: 10px;\"><code> class SomeComponent {\r\n-    show() {\r\n-        \/\/ ...\r\n-    }\r\n-    hide() {\r\n-        \/\/ ...\r\n-    }\r\n+    setVisible(value: boolean) {\r\n+        \/\/ ...\r\n+    }\r\n }\r\n class SpecializedComponent extends SomeComponent {\r\n     show() {\r\n         \/\/ ...\r\n     }\r\n     hide() {\r\n         \/\/ ...\r\n     }\r\n }\r\n<\/code><\/pre>\n<p><em>Oh no!<\/em>\nOur <code>SpecializedComponent<\/code> didn&#8217;t get updated.\nNow it&#8217;s just adding these two useless <code>show<\/code> and <code>hide<\/code> methods that probably won&#8217;t get called.<\/p>\n<p>Part of the issue here is that a user can&#8217;t make it clear whether they meant to add a new method, or to override an existing one.\nThat&#8217;s why TypeScript 4.3 adds the <code>override<\/code> keyword.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class SpecializedComponent extends SomeComponent {\r\n    override show() {\r\n        \/\/ ...\r\n    }\r\n    override hide() {\r\n        \/\/ ...\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>When a method is marked with <code>override<\/code>, TypeScript will always make sure that a method with the same name exists in a the base class.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class SomeComponent {\r\n    setVisible(value: boolean) {\r\n        \/\/ ...\r\n    }\r\n}\r\nclass SpecializedComponent extends SomeComponent {\r\n    override show() {\r\n\/\/  ~~~~~~~~\r\n\/\/ Error! This method can't be marked with 'override' because it's not declared in 'SomeComponent'.\r\n        \/\/ ...\r\n    }\r\n\r\n    \/\/ ...\r\n}\r\n<\/code><\/pre>\n<p>This is a big improvement, but it doesn&#8217;t help if you <em>forget<\/em> to write <code>override<\/code> on a method &#8211; and that&#8217;s a big mistake users can run into also.<\/p>\n<p>For example, you might accidentally &#8220;trample over&#8221; a method that exists in a base class without realizing it.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Base {\r\n    someHelperMethod() {\r\n        \/\/ ...\r\n    }\r\n}\r\n\r\nclass Derived extends Base {\r\n    \/\/ Oops! We weren't trying to override here,\r\n    \/\/ we just needed to write a local helper method.\r\n    someHelperMethod() {\r\n        \/\/ ...\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>That&#8217;s why TypeScript 4.3 <em>also<\/em> provides a new <code>--noImplicitOverride<\/code> flag.\nWhen this option is turned on, it becomes an error to override any method from a superclass unless you explicitly use an <code>override<\/code> keyword.\nIn that last example, TypeScript would error under <code>--noImplicitOverride<\/code>, and give us a clue that we probably need to rename our method inside of <code>Derived<\/code>.<\/p>\n<p>We&#8217;d like to extend our thanks to our community for the implementation here.\nThe work for these items was implemented in <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/39669\">a pull request<\/a> by <a href=\"https:\/\/github.com\/Kingwl\">Wenlu Wang<\/a>, though an earlier pull request implementing only the <code>override<\/code> keyword by <a href=\"https:\/\/github.com\/pcj\">Paul Cody Johnston<\/a> served as a basis for direction and discussion.\nWe extend our gratitude for putting in the time for these features.<\/p>\n<h2 id=\"template-string-type-improvements\"><a name=\"template-string-improvements\"><\/a> Template String Type Improvements<\/h2>\n<p>In recent versions, TypeScript introduced a new type construct: template string types.\nThese are types that either construct new string-like types by concatenating&#8230;<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>type Color = \"red\" | \"blue\";\r\ntype Quantity = \"one\" | \"two\";\r\n\r\ntype SeussFish = `${Quantity | Color} fish`;\r\n\/\/ same as\r\n\/\/   type SeussFish = \"one fish\" | \"two fish\"\r\n\/\/                  | \"red fish\" | \"blue fish\";\r\n<\/code><\/pre>\n<p>&#8230;or match patterns of other string-like types.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>declare let s1: `${number}-${number}-${number}`;\r\ndeclare let s2: `1-2-3`;\r\n\r\n\/\/ Works!\r\ns1 = s2;\r\n<\/code><\/pre>\n<p>The first change we made is just in when TypeScript will infer a template string type.\nWhen a template string is <em>contextually typed<\/em> by a string-literal-like type (i.e. when TypeScript sees we&#8217;re passing a template string to something that takes a literal type) it will try to give that expression a template type.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>function bar(s: string): `hello ${string}` {\r\n    \/\/ Previously an error, now works!\r\n    return `hello ${s}`;\r\n}\r\n<\/code><\/pre>\n<p>This also kicks in when inferring types, and the type parameter <code>extends string<\/code><\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>declare let s: string;\r\ndeclare function f&lt;T extends string&gt;(x: T): T;\r\n\r\n\/\/ Previously: string\r\n\/\/ Now       : `hello-${string}`\r\nlet x2 = f(`hello ${s}`);\r\n<\/code><\/pre>\n<p>The second major change here is that TypeScript can now better-relate, and <em>infer between<\/em>, different template string types.<\/p>\n<p>To see this, take the following example code:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>declare let s1: `${number}-${number}-${number}`;\r\ndeclare let s2: `1-2-3`;\r\ndeclare let s3: `${number}-2-3`;\r\n\r\ns1 = s2;\r\ns1 = s3;\r\n<\/code><\/pre>\n<p>When checking against a string literal type like on <code>s2<\/code>, TypeScript could match against the string contents and figure out that <code>s2<\/code> was compatible with <code>s1<\/code> in the first assignment;\nhowever, as soon as it saw another template string, it just gave up.\nAs a result, assignments like <code>s3<\/code> to <code>s1<\/code> just didn&#8217;t work.<\/p>\n<p>TypeScript now actually does the work to prove whether or not each part of a template string can successfully match.\nYou can now mix and match template strings with different substitutions and TypeScript will do a good job to figure out whether they&#8217;re really compatible.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>declare let s1: `${number}-${number}-${number}`;\r\ndeclare let s2: `1-2-3`;\r\ndeclare let s3: `${number}-2-3`;\r\ndeclare let s4: `1-${number}-3`;\r\ndeclare let s5: `1-2-${number}`;\r\ndeclare let s6: `${number}-2-${number}`;\r\n\r\n\/\/ Now *all of these* work!\r\ns1 = s2;\r\ns1 = s3;\r\ns1 = s4;\r\ns1 = s5;\r\ns1 = s6;\r\n<\/code><\/pre>\n<p>In doing this work, we were also sure to add better inference capabilities.\nYou can see an example of these in action:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>declare function foo&lt;V extends string&gt;(arg: `*${V}*`): V;\r\n\r\nfunction test&lt;T extends string&gt;(s: string, n: number, b: boolean, t: T) {\r\n    let x1 = foo(\"*hello*\");            \/\/ \"hello\"\r\n    let x2 = foo(\"**hello**\");          \/\/ \"*hello*\"\r\n    let x3 = foo(`*${s}*` as const);    \/\/ string\r\n    let x4 = foo(`*${n}*` as const);    \/\/ `${number}`\r\n    let x5 = foo(`*${b}*` as const);    \/\/ \"true\" | \"false\"\r\n    let x6 = foo(`*${t}*` as const);    \/\/ `${T}`\r\n    let x7 = foo(`**${s}**` as const);  \/\/ `*${string}*`\r\n}\r\n<\/code><\/pre>\n<p>For more information, see <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43376\">the original pull request on leveraging contextual types<\/a>, along with <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43361\">the pull request that improved inference and checking between template types<\/a>.<\/p>\n<h2 id=\"ecmascript-private-class-elements\"><a name=\"private-elements\"><\/a> ECMAScript <code>#private<\/code> Class Elements<\/h2>\n<p>TypeScript 4.3 expands which elements in a class can be given <code>#private<\/code> <code>#names<\/code> to make them truly private at run-time.\nIn addition to properties, methods and accessors can also be given private names.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Foo {\r\n    #someMethod() {\r\n        \/\/...\r\n    }\r\n\r\n    get #someValue() {\r\n        return 100;\r\n    }\r\n\r\n    publicMethod() {\r\n        \/\/ These work.\r\n        \/\/ We can access private-named members inside this class.\r\n        this.#someMethod();\r\n        return this.#someValue;\r\n    }\r\n}\r\n\r\nnew Foo().#someMethod();\r\n\/\/        ~~~~~~~~~~~\r\n\/\/ error!\r\n\/\/ Property '#someMethod' is not accessible\r\n\/\/ outside class 'Foo' because it has a private identifier.\r\n\r\nnew Foo().#someValue;\r\n\/\/        ~~~~~~~~~~\r\n\/\/ error!\r\n\/\/ Property '#someValue' is not accessible\r\n\/\/ outside class 'Foo' because it has a private identifier.\r\n<\/code><\/pre>\n<p>Even more broadly, static members can now also have private names.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Foo {\r\n    static #someMethod() {\r\n        \/\/ ...\r\n    }\r\n}\r\n\r\nFoo.#someMethod();\r\n\/\/  ~~~~~~~~~~~\r\n\/\/ error!\r\n\/\/ Property '#someMethod' is not accessible\r\n\/\/ outside class 'Foo' because it has a private identifier.\r\n<\/code><\/pre>\n<p>This feature was authored <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/42458\">in a pull request<\/a> from our friends at Bloomberg &#8211; written by <a href=\"https:\/\/github.com\/dragomirtitian\">Titian Cernicova-Dragomir<\/a>and <a href=\"https:\/\/github.com\/mkubilayk\">Kubilay Kahveci<\/a>, with support and expertise from <a href=\"https:\/\/github.com\/joeywatts\">Joey Watts<\/a>, <a href=\"https:\/\/github.com\/robpalme\">Rob Palmer<\/a>, and <a href=\"https:\/\/github.com\/tim-mc\">Tim McClure<\/a>.\nWe&#8217;d like to extend our thanks to all of them!<\/p>\n<h2 id=\"constructorparameters-works-on-abstract-classes\"><a name=\"constructor-parameters\"><\/a> <code>ConstructorParameters<\/code> Works on Abstract Classes<\/h2>\n<p>In TypeScript 4.3, the <code>ConstructorParameters<\/code> type helper now works on <code>abstract<\/code> classes.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>abstract class C {\r\n    constructor(a: string, b: number) {\r\n        \/\/ ...\r\n    }\r\n}\r\n\r\n\/\/ Has the type '[a: string, b: number]'.\r\ntype CParams = ConstructorParameters&lt;typeof C&gt;;\r\n<\/code><\/pre>\n<p>This is thanks to work done in TypeScript 4.2, where construct signatures can be marked as abstract:<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>type MyConstructorOf&lt;T&gt; = {\r\n    abstract new(...args: any[]): T;\r\n}\r\n\r\n\/\/ or using the shorthand syntax:\r\n\r\ntype MyConstructorOf&lt;T&gt; = abstract new (...args: any[]) =&gt; T;\r\n<\/code><\/pre>\n<p>You can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43380\">see the change in more detail on GitHub<\/a>.<\/p>\n<h2 id=\"contextual-narrowing-for-generics\"><a name=\"contextual-narrowing\"><\/a> Contextual Narrowing for Generics<\/h2>\n<p>TypeScript 4.3 now includes some slightly smarter type-narrowing logic on generic values.\nThis allows TypeScript to accept more patterns, and sometimes even catch mistakes.<\/p>\n<p>For some motivation, let&#8217;s say we&#8217;re trying to write a function called <code>makeUnique<\/code>.\nIt&#8217;ll take a <code>Set<\/code> or an <code>Array<\/code> of elements, and if it&#8217;s given an <code>Array<\/code>, it&#8217;ll sort that <code>Array<\/code> remove duplicates according to some comparison function.\nAfter all that, it will return the original collection.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>function makeUnique&lt;T&gt;(collection: Set&lt;T&gt; | T[], comparer: (x: T, y: T) =&gt; number): Set&lt;T&gt; | T[] {\r\n  \/\/ Early bail-out if we have a Set.\r\n  \/\/ We assume the elements are already unique.\r\n  if (collection instanceof Set) {\r\n    return collection;\r\n  }\r\n\r\n  \/\/ Sort the array, then remove consecutive duplicates.\r\n  collection.sort(comparer);\r\n  for (let i = 0; i &lt; collection.length; i++) {\r\n    let j = i;\r\n    while (j &lt; collection.length &amp;&amp; comparer(collection[i], collection[j + 1]) === 0) {\r\n      j++;\r\n    }\r\n    collection.splice(i + 1, j - i);\r\n  }\r\n  return collection;\r\n}\r\n<\/code><\/pre>\n<p>Let&#8217;s leave questions about this function&#8217;s implementation aside, and assume it arose from the requirements of a broader application.\nSomething that you might notice is that the signature doesn&#8217;t capture the original type of <code>collection<\/code>.\nWe can do that by adding a type parameter called <code>C<\/code> in place of where we&#8217;ve written <code>Set&lt;T&gt; | T[]<\/code>.<\/p>\n<pre class=\"prettyprint language-diff\" style=\"padding: 10px; border-radius: 10px;\"><code>- function makeUnique&lt;T&gt;(collection: Set&lt;T&gt; | T[], comparer: (x: T, y: T) =&gt; number): Set&lt;T&gt; | T[]\r\n+ function makeUnique&lt;T, C extends Set&lt;T&gt; | T[]&gt;(collection: C, comparer: (x: T, y: T) =&gt; number): C\r\n<\/code><\/pre>\n<p>In TypeScript 4.2 and earlier, you&#8217;d end up with a bunch of errors as soon as you tried this.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>function makeUnique&lt;T, C extends Set&lt;T&gt; | T[]&gt;(collection: C, comparer: (x: T, y: T) =&gt; number): C {\r\n  \/\/ Early bail-out if we have a Set.\r\n  \/\/ We assume the elements are already unique.\r\n  if (collection instanceof Set) {\r\n    return collection;\r\n  }\r\n\r\n  \/\/ Sort the array, then remove consecutive duplicates.\r\n  collection.sort(comparer);\r\n  \/\/         ~~~~\r\n  \/\/ error: Property 'sort' does not exist on type 'C'.\r\n  for (let i = 0; i &lt; collection.length; i++) {\r\n  \/\/                             ~~~~~~\r\n  \/\/ error: Property 'length' does not exist on type 'C'.\r\n    let j = i;\r\n    while (j &lt; collection.length &amp;&amp; comparer(collection[i], collection[j + 1]) === 0) {\r\n    \/\/                    ~~~~~~\r\n    \/\/ error: Property 'length' does not exist on type 'C'.\r\n    \/\/                                       ~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~\r\n    \/\/ error: Element implicitly has an 'any' type because expression of type 'number'\r\n    \/\/        can't be used to index type 'Set&lt;T&gt; | T[]'.\r\n      j++;\r\n    }\r\n    collection.splice(i + 1, j - i);\r\n    \/\/         ~~~~~~\r\n    \/\/ error: Property 'splice' does not exist on type 'C'.\r\n  }\r\n  return collection;\r\n}\r\n<\/code><\/pre>\n<p>Ew, errors!\nWhy is TypeScript being so mean to us?<\/p>\n<p>The issue is that when we perform our <code>collection instanceof Set<\/code> check, we&#8217;re expecting that to act as a type guard that narrows the type from <code>Set&lt;T&gt; | T[]<\/code> to <code>Set&lt;T&gt;<\/code> and <code>T[]<\/code> depending on the branch we&#8217;re in;\nhowever, we&#8217;re not dealing with a <code>Set&lt;T&gt; | T[]<\/code>, we&#8217;re trying to narrow the generic value <code>collection<\/code>, whose type is <code>C<\/code>.<\/p>\n<p>It&#8217;s a very subtle distinction, but it makes a difference.\nTypeScript can&#8217;t just grab the constraint of <code>C<\/code> (which is <code>Set&lt;T&gt; | T[]<\/code>) and narrow that.\nIf TypeScript <em>did<\/em> try to narrow from <code>Set&lt;T&gt; | T[]<\/code>, it would forget that <code>collection<\/code> is also a <code>C<\/code> in each branch because there&#8217;s no easy way to preserve that information.\nIf hypothetically TypeScript tried that approach, it would break the above example in a different way.\nAt the return positions, where the function expects values with the type <code>C<\/code>, we would instead get a <code>Set&lt;T&gt;<\/code> and a <code>T[]<\/code> in each branch, which TypeScript would reject.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>function makeUnique&lt;T&gt;(collection: Set&lt;T&gt; | T[], comparer: (x: T, y: T) =&gt; number): Set&lt;T&gt; | T[] {\r\n  \/\/ Early bail-out if we have a Set.\r\n  \/\/ We assume the elements are already unique.\r\n  if (collection instanceof Set) {\r\n    return collection;\r\n    \/\/     ~~~~~~~~~~\r\n    \/\/ error: Type 'Set&lt;T&gt;' is not assignable to type 'C'.\r\n    \/\/          'Set&lt;T&gt;' is assignable to the constraint of type 'C', but\r\n    \/\/          'C' could be instantiated with a different subtype of constraint 'Set&lt;T&gt; | T[]'.\r\n  }\r\n\r\n  \/\/ ...\r\n\r\n  return collection;\r\n  \/\/     ~~~~~~~~~~\r\n  \/\/ error: Type 'T[]' is not assignable to type 'C'.\r\n  \/\/          'T[]' is assignable to the constraint of type 'C', but\r\n  \/\/          'C' could be instantiated with a different subtype of constraint 'Set&lt;T&gt; | T[]'.\r\n  }\r\n<\/code><\/pre>\n<p>So how does TypeScript 4.3 change things?\nWell, basically in a few key places when writing code, all the type system really cares about is the constraint of a type.\nFor example, when we write <code>collection.length<\/code>, TypeScript doesn&#8217;t care about the fact that <code>collection<\/code> has the type <code>C<\/code>, it only cares about the properties available, which are determined by the constraint <code>T[] | Set&lt;T&gt;<\/code>.<\/p>\n<p>In cases like this, TypeScript will grab the narrowed type of the constraint because that will give you the data you care about;\nhowever, in any other case, we&#8217;ll just try to narrow the original generic type (and often end up with the original generic type).<\/p>\n<p>In other words, based on how you use a generic value, TypeScript will narrow it a little differently.\nThe end result is that the entire above example compiles with no type-checking errors.<\/p>\n<p>For more details, you can <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43183\">look at the original pull request on GitHub<\/a>.<\/p>\n<h2 id=\"always-truthy-promise-checks\"><a name=\"truthy-promise-checks\"><\/a> Always-Truthy Promise Checks<\/h2>\n<p>Under <code>strictNullChecks<\/code>, checking whether a <code>Promise<\/code> is &#8220;truthy&#8221; in a conditional will trigger an error.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>async function foo(): Promise&lt;boolean&gt; {\r\n    return false;\r\n}\r\n\r\nasync function bar(): Promise&lt;string&gt; {\r\n    if (foo()) {\r\n    \/\/  ~~~~~\r\n    \/\/ Error!\r\n    \/\/ This condition will always return true since\r\n    \/\/ this 'Promise&lt;boolean&gt;' appears to always be defined.\r\n    \/\/ Did you forget to use 'await'?\r\n        return \"true\";\r\n    }\r\n    return \"false\";\r\n}\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/39175\">This change<\/a> was contributed by <a href=\"https:\/\/github.com\/Jack-Works\">Jack Works<\/a>, and we extend our thanks to them!<\/p>\n<h2 id=\"static-index-signatures\"><a name=\"static-index-signatures\"><\/a> <code>static<\/code> Index Signatures<\/h2>\n<p>Index signatures allow us set more properties on a value than a type explicitly declares.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Foo {\r\n    hello = \"hello\";\r\n    world = 1234;\r\n\r\n    \/\/ This is an index signature:\r\n    [propName: string]: string | number | undefined;\r\n}\r\n\r\nlet instance = new Foo();\r\n\r\n\/\/ Valid assigment\r\ninstance[\"whatever\"] = 42;\r\n\r\n\/\/ Has type 'string | number | undefined'.\r\nlet x = instance[\"something\"];\r\n<\/code><\/pre>\n<p>Up until now, an index signature could only be declared on the instance side of a class.\nThanks to <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/37797\">a pull request<\/a> from <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/37797\">Wenlu Wang<\/a>, index signatures can now be declared as <code>static<\/code>.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Foo {\r\n    static hello = \"hello\";\r\n    static world = 1234;\r\n\r\n    static [propName: string]: string | number | undefined;\r\n}\r\n\r\n\/\/ Valid.\r\nFoo[\"whatever\"] = 42;\r\n\r\n\/\/ Has type 'string | number | undefined'\r\nlet x = Foo[\"something\"];\r\n<\/code><\/pre>\n<p>The same sorts of rules apply for index signatures on the static side of a class as they do for the instance side &#8211; namely, that every other static property has to be compatible with the index signature.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>class Foo {\r\n    static prop = true;\r\n    \/\/     ~~~~\r\n    \/\/ Error! Property 'prop' of type 'boolean'\r\n    \/\/ is not assignable to string index type\r\n    \/\/ 'string | number | undefined'.\r\n\r\n    static [propName: string]: string | number | undefined;\r\n}\r\n<\/code><\/pre>\n<h2 id=\"tsbuildinfo-size-improvements\"><a name=\"tsbuildinfo-is-smol\"><\/a> <code>.tsbuildinfo<\/code> Size Improvements<\/h2>\n<p>In TypeScript 4.3, <code>.tsbuildinfo<\/code> files that are generated as part of <code>--incremental<\/code> builds should be significantly smaller.\nThis is thanks to several optimizations in the internal format, creating tables with numeric identifiers to be used throughout the file instead of repeating full paths and similar information.\nThis work was spear-headed by <a href=\"https:\/\/github.com\/sokra\">Tobias Koppers<\/a> in <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43079\">their pull request<\/a>, serving as inspiration for <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43155\">the ensuing pull request<\/a> and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43695\">further optimizations<\/a>.<\/p>\n<p>We have seen significant reductions of <code>.tsbuildinfo<\/code> file sizes including<\/p>\n<ul>\n<li>1MB to 411 KB<\/li>\n<li>14.9MB to 1MB<\/li>\n<li>1345MB to 467MB<\/li>\n<\/ul>\n<p>Needless to say, these sorts of savings in size translate to slightly faster build times as well.<\/p>\n<h2 id=\"lazier-calculations-in---incremental-and---watch-compilations\"><a name=\"lazier-incremental\"><\/a> Lazier Calculations in <code>--incremental<\/code> and <code>--watch<\/code> Compilations<\/h2>\n<p>One of the issues with <code>--incremental<\/code> and <code>--watch<\/code> modes are that while they make later compilations go faster, the initial compilation can be a bit slower &#8211; in some cases, significantly slower.\nThis is because these modes have to perform a bunch of book-keeping, computing information about the current project, and sometimes saving that data in a <code>.tsbuildinfo<\/code> file for later builds.<\/p>\n<p>That&#8217;s why on top of <code>.tsbuildinfo<\/code> size improvements, TypeScript 4.3 also ships some changes to <code>--incremental<\/code> and <code>--watch<\/code> modes that make the first build of a project with these flags just as fast as an ordinary build!\nTo do this, much of the information that would ordinarily be computed up-front is instead done on an on-demand basis for later builds.\nWhile this can add some overhead to a subsequent build, TypeScript&#8217;s <code>--incremental<\/code> and <code>--watch<\/code> functionality will still typically operate on a much smaller set of files, and any needed information will be saved afterwards.\nIn a sense, <code>--incremental<\/code> and <code>--watch<\/code> builds will &#8220;warm up&#8221; and get faster at compiling files once you&#8217;ve updated them a few times.<\/p>\n<p>In a repository with 3000 files, <strong>this reduced initial build times to almost a third<\/strong>!<\/p>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/42960\">This work was started<\/a> by <a href=\"https:\/\/github.com\/sokra\">Tobias Koppers<\/a>, whose work ensued in <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43314\">the resulting final change<\/a> for this functionality.\nWe&#8217;d like to extend a great thanks to Tobias for helping us find these opportunities for improvements!<\/p>\n<h2 id=\"import-statement-completions\"><a name=\"import-statement-completions\"><\/a> Import Statement Completions<\/h2>\n<p>One of the biggest pain-points users run into with import and export statements in JavaScript is the order &#8211; specifically that imports are written as<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>import { func } from \".\/module.js\";\r\n<\/code><\/pre>\n<p>instead of<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>from \".\/module.js\" import { func };\r\n<\/code><\/pre>\n<p>This causes some pain when writing out a full import statement from scratch because auto-complete wasn&#8217;t able to work correctly.\nFor example, if you start writing something like <code>import {<\/code>, TypeScript has no idea what module you&#8217;re planning on importing from, so it couldn&#8217;t provide any scoped-down completions.<\/p>\n<p>To alleviate this, we&#8217;ve leveraged the power of auto-imports!\nAuto-imports already deal with the issue of not being able to narrow down completions from a specific module &#8211; their whole point is to provide every possible export and automatically insert an import statement at the top of your file.<\/p>\n<p>So when you now start writing an <code>import<\/code> statement that doesn&#8217;t have a path, we&#8217;ll provide you with a list of possible imports.\nWhen you commit a completion, we&#8217;ll complete the full import statement, including the path that you were going to write.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/05\/auto-import-statement-4-3.gif\" alt=\"Import statement completions\" \/><\/p>\n<p>This work requires editors that specifically support the feature.\nYou&#8217;ll be able to try this out by using the latest <a href=\"https:\/\/code.visualstudio.com\/insiders\/\">Insiders versions of Visual Studio Code<\/a>.<\/p>\n<p>For more information, take a look at <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/43149\">the implementing pull request<\/a>!<\/p>\n<h2 id=\"editor-support-for-link-tags\"><a name=\"jsdoc-link-tags\"><\/a> Editor Support for <code>@link<\/code> Tags<\/h2>\n<p>TypeScript can now understand <code>@link<\/code> tags, and will try to resolve declarations that they link to.\nWhat this means is that you&#8217;ll be able to hover over names within <code>@link<\/code> tags and get quick information, or use commands like go-to-definition or find-all-references.<\/p>\n<p>For example, you&#8217;ll be able to go-to-definition on <code>plantCarrot<\/code> in <code>@link plantCarrot<\/code> in the example below and a TypeScript-supported editor will jump to <code>bar<\/code>&#8216;s function declaration.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>\/**\r\n * To be called 70 to 80 days after {@link plantCarrot}.\r\n *\/\r\nfunction harvestCarrot(carrot: Carrot) {\r\n\r\n}\r\n\r\n\/**\r\n * Call early in spring for best results. Added in v2.1.0.\r\n * @param seed Make sure it's a carrot seed!\r\n *\/\r\nfunction plantCarrot(seed: Seed) {\r\n    \/\/ TODO: some gardening\r\n}\r\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/typescript\/wp-content\/uploads\/sites\/11\/2021\/05\/link-tag-4-3.gif\" alt=\"Jumping to definition and requesting quick info on a tag for \" \/><\/p>\n<p>For more information, see <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/41877\">the pull request on GitHub<\/a>!<\/p>\n<h2 id=\"go-to-definition-on-non-javascript-file-paths\"><a name=\"go-to-def-non-js\"><\/a> Go-to-Definition on Non-JavaScript File Paths<\/h2>\n<p>Many loaders allow users to include assets in their applications using JavaScript imports.\nThey&#8217;ll typically be written as something like <code>import \".\/styles.css\"<\/code> or the like.<\/p>\n<p>Up until now, TypeScript&#8217;s editor functionality wouldn&#8217;t even attempt to read this file, so go-to-definition would typically fail.\nAt best, go-to-definition would jump to a declaration like <code>declare module \"*.css\"<\/code> if it could find something along those lines.<\/p>\n<p>TypeScript&#8217;s language service now tries to jump to the correct file when you perform a go-to-definition on relative file paths, even if they&#8217;re not JavaScript or TypeScript files!\nTry it out with imports to CSS, SVGs, PNGs, font files, Vue files, and more.<\/p>\n<p>For more information, you can check out <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/42539\">the implementing pull request<\/a>.<\/p>\n<h2 id=\"breaking-changes\"><a name=\"breaking-changes\"><\/a> Breaking Changes<\/h2>\n<h3 id=\"libdts-changes\"><code>lib.d.ts<\/code> Changes<\/h3>\n<p>As with every TypeScript version, declarations for <code>lib.d.ts<\/code> (especially the declarations generated for web contexts), have changed.\nIn this release, we leveraged <a href=\"https:\/\/github.com\/mdn\/browser-compat-data\">Mozilla&#8217;s browser-compat-data<\/a> to remove APIs that no browser implements.\nWhile it is unlike that you are using them, APIs such as <code>Account<\/code>, <code>AssertionOptions<\/code>, <code>RTCStatsEventInit<\/code>, <code>MSGestureEvent<\/code>, <code>DeviceLightEvent<\/code>, <code>MSPointerEvent<\/code>, <code>ServiceWorkerMessageEvent<\/code>, and <code>WebAuthentication<\/code> have all been removed from <code>lib.d.ts<\/code>.\nThis is discussed <a href=\"https:\/\/github.com\/microsoft\/TypeScript-DOM-lib-generator\/issues\/991\">in some detail here<\/a>.<\/p>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript-DOM-lib-generator\/issues\/991\">https:\/\/github.com\/microsoft\/TypeScript-DOM-lib-generator\/issues\/991<\/a><\/p>\n<h3 id=\"errors-on-always-truthy-promise-checks\">Errors on Always-Truthy Promise Checks<\/h3>\n<p>Under <code>strictNullChecks<\/code>, using a <code>Promise<\/code> that always appears to be defined within a condition check is now considered an error.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>declare var p: Promise&lt;number&gt;;\r\n\r\nif (p) {\r\n\/\/  ~\r\n\/\/ Error!\r\n\/\/ This condition will always return true since\r\n\/\/ this 'Promise&lt;number&gt;' appears to always be defined.\r\n\/\/\r\n\/\/ Did you forget to use 'await'?\r\n}\r\n<\/code><\/pre>\n<p>For more details, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/39175\">see the original change<\/a>.<\/p>\n<h3 id=\"union-enums-cannot-be-compared-to-arbitrary-numbers\">Union Enums Cannot Be Compared to Arbitrary Numbers<\/h3>\n<p>Certain <code>enum<\/code>s are considered <em>union <code>enum<\/code>s<\/em> when their members are either automatically filled in, or trivially written.\nIn those cases, an enum can recall each value that it potentially represents.<\/p>\n<p>In TypeScript 4.3, if a value with a union <code>enum<\/code> type is compared with a numeric literal that it could never be equal to, then the type-checker will issue an error.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>enum E {\r\n  A = 0,\r\n  B = 1,\r\n}\r\n\r\nfunction doSomething(x: E) {\r\n  \/\/ Error! This condition will always return 'false' since the types 'E' and '-1' have no overlap.\r\n  if (x === -1) {\r\n    \/\/ ...\r\n  }\r\n}\r\n<\/code><\/pre>\n<p>As a workaround, you can re-write an annotation to include the appropriate literal type.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>enum E {\r\n  A = 0,\r\n  B = 1,\r\n}\r\n\r\n\/\/ Include -1 in the type, if we're really certain that -1 can come through.\r\nfunction doSomething(x: E | -1) {\r\n  if (x === -1) {\r\n    \/\/ ...\r\n  }\r\n}\r\n<\/code><\/pre>\n<p>You can also use a type-assertion on the value.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>enum E {\r\n  A = 0,\r\n  B = 1,\r\n}\r\n\r\nfunction doSomething(x: E) {\r\n  \/\/ Use a type asertion on 'x' because we know we're not actually just dealing with values from 'E'.\r\n  if ((x as number) === -1) {\r\n    \/\/ ...\r\n  }\r\n}\r\n<\/code><\/pre>\n<p>Alternatively, you can re-declare your enum to have a non-trivial initializer so that any number is both assignable and comparable to that enum. This may be useful if the intent is for the enum to specify a few well-known values.<\/p>\n<pre class=\"prettyprint language-typescript\" style=\"padding: 10px; border-radius: 10px;\"><code>enum E {\r\n  \/\/ the leading + on 0 opts TypeScript out of inferring a union enum.\r\n  A = +0,\r\n  B = 1,\r\n}\r\n<\/code><\/pre>\n<p>For more details, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/42472\">see the original change<\/a><\/p>\n<h2 id=\"whats-next\"><a name=\"whats-next\"><\/a> What&#8217;s Next?<\/h2>\n<p>TypeScript 4.3 is out now, but our team is already hard at work on TypeScript 4.4.\nYou can track our release dates and upcoming features by following the <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/44237\">TypeScript 4.4 Iteration Plan<\/a>, and follow some of the progress by watching the <a href=\"https:\/\/github.com\/Microsoft\/TypeScript\/wiki\/Roadmap\">TypeScript Rolling Feature Roadmap<\/a>.\nIf you can&#8217;t wait to try some of our new features, we encourage you to <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/nightly-builds.html\">try and give feedback on our nightly builds<\/a> which tend to be very stable.<\/p>\n<p>Don&#8217;t feel rushed though &#8211; we&#8217;ve worked hard to make sure TypeScript 4.3 is a solid release.\nWe hope that it makes your day-to-day coding a joy.<\/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 availability of TypeScript 4.3! If you&#8217;re not yet familiar with TypeScript, it&#8217;s a language that builds on JavaScript by adding syntax for static types. Tools like the TypeScript compiler can just erase TypeScript syntax, leaving you with clean readable JavaScript that works anywhere. So what&#8217;s that syntax adding if [&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-2984","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 availability of TypeScript 4.3! If you&#8217;re not yet familiar with TypeScript, it&#8217;s a language that builds on JavaScript by adding syntax for static types. Tools like the TypeScript compiler can just erase TypeScript syntax, leaving you with clean readable JavaScript that works anywhere. So what&#8217;s that syntax adding if [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/2984","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=2984"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/2984\/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=2984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=2984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=2984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}