{"id":2766,"date":"2020-09-18T11:54:47","date_gmt":"2020-09-18T19:54:47","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/typescript\/?p=2766"},"modified":"2020-09-18T14:27:08","modified_gmt":"2020-09-18T22:27:08","slug":"announcing-typescript-4-1-beta","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/typescript\/announcing-typescript-4-1-beta\/","title":{"rendered":"Announcing TypeScript 4.1 Beta"},"content":{"rendered":"<p>Today we&#8217;re announcing the availability of TypeScript 4.1 Beta!<\/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 use 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-41beta\" 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>For this release, we have some exciting new features, new checking flags, editor productivity updates, and speed improvements. Let&#8217;s get a look at what 4.1 has in store for us!<\/p>\n<ul>\n<li><a href=\"#template-literal-types\">Template Literal Types<\/a><\/li>\n<li><a href=\"#key-remapping-mapped-types\">Key Remapping in Mapped Types<\/a><\/li>\n<li><a href=\"#recursive-conditional-types\">Recursive Conditional Types<\/a><\/li>\n<li><a href=\"#no-unchecked-indexed-access\"><code>--noUncheckedIndexedAccess<\/code><\/a><\/li>\n<li><a href=\"#template-literal-types\"><code>paths<\/code> without <code>baseUrl<\/code><\/a><\/li>\n<li><a href=\"#checkjs-implies-allowjs\"><code>checkJs<\/code> Implies <code>allowJs<\/code><\/a><\/li>\n<li><a href=\"#jsx-factories\">React 17 JSX Factories<\/a><\/li>\n<li><a href=\"#jsdoc-see-tag\">Editor Support for the JSDoc <code>@see<\/code> Tag<\/a><\/li>\n<li><a href=\"#breaking-changes\">Breaking Changes<\/a><\/li>\n<\/ul>\n<h2 id=\"template-literal-types\">Template Literal Types<\/h2>\n<p>String literal types in TypeScript allow us to model functions and APIs that expect a set of specific strings.<\/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;\">function<\/span> <span class=\"pl-en\">setVerticalAlignment<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">color<\/span>: <span style=\"color: #a31515;\">\"top\"<\/span> | <span style=\"color: #a31515;\">\"middle\"<\/span> | <span style=\"color: #a31515;\">\"bottom\"<\/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 class=\"pl-en\">setVerticalAlignment<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"middel\"<\/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: Argument of type '\"middel\"' is not assignable to<\/span>\r\n<span style=\"color: #148A14;\">\/\/        parameter of type '\"top\" | \"middle\" | \"bottom\"'.<\/span><\/pre>\n<\/div>\n<p>This is pretty nice because string literal types can basically spell-check our string values.<\/p>\n<p>We also like that string literals can be used as property names in mapped types. In this sense, they&#8217;re also usable as building blocks.<\/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;\">type<\/span> <span style=\"color: #267F99;\">Options<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span> <span style=\"color: #0000ff;\">in<\/span> <span style=\"color: #a31515;\">\"noImplicitAny\"<\/span> | <span style=\"color: #a31515;\">\"strictNullChecks\"<\/span> | <span style=\"color: #a31515;\">\"strictFunctionTypes\"<\/span><span class=\"pl-kos\">]<\/span>?: <span style=\"color: #0000ff;\">boolean<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/ same as<\/span>\r\n<span style=\"color: #148A14;\">\/\/   type Options = {<\/span>\r\n<span style=\"color: #148A14;\">\/\/       noImplicitAny?: boolean,<\/span>\r\n<span style=\"color: #148A14;\">\/\/       strictNullChecks?: boolean,<\/span>\r\n<span style=\"color: #148A14;\">\/\/       strictFunctionTypes?: boolean<\/span>\r\n<span style=\"color: #148A14;\">\/\/   };<\/span><\/pre>\n<\/div>\n<p>But there&#8217;s another place that that string literal types could be used as building blocks: building other string literal types.<\/p>\n<p>That&#8217;s why TypeScript 4.1 brings the template literal string type. It has the same syntax as <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Template_literals\" rel=\"nofollow\">template literal strings in JavaScript<\/a>, but is used in type positions. When you use it with concrete literal types, it produces a new string literal type by concatenating the contents.<\/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;\">type<\/span> <span style=\"color: #267F99;\">World<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"world\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-en\">type<\/span> <span style=\"color: #267F99;\">Greeting<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">`hello <span class=\"pl-s1\"><span class=\"pl-kos\">${<\/span><span style=\"color: #267F99;\">World<\/span><span class=\"pl-kos\">}<\/span><\/span>`<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/ same as<\/span>\r\n<span style=\"color: #148A14;\">\/\/   type Greeting = \"hello world\";<\/span><\/pre>\n<\/div>\n<p>What happens when you have unions in substitution positions? It produces the set of every possible string literal that could be represented by each union 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;\">type<\/span> <span style=\"color: #267F99;\">Color<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"red\"<\/span> | <span style=\"color: #a31515;\">\"blue\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">Quantity<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"one\"<\/span> | <span style=\"color: #a31515;\">\"two\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-en\">type<\/span> <span style=\"color: #267F99;\">SeussFish<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">`<span class=\"pl-s1\"><span class=\"pl-kos\">${<\/span><span style=\"color: #267F99;\">Quantity<\/span> | <span style=\"color: #267F99;\">Color<\/span><span class=\"pl-kos\">}<\/span><\/span> fish`<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/ same as<\/span>\r\n<span style=\"color: #148A14;\">\/\/   type SeussFish = \"one fish\" | \"two fish\"<\/span>\r\n<span style=\"color: #148A14;\">\/\/                  | \"red fish\" | \"blue fish\";<\/span><\/pre>\n<\/div>\n<p>This can be used beyond cute examples in release notes. For example, several libraries for UI components have a way to specify both vertical and horizontal alignment in their APIs, often with both at once using a single string like <code>\"bottom-right\"<\/code>. Between vertically aligning with <code>\"top\"<\/code>, <code>\"middle\"<\/code>, and <code>\"bottom\"<\/code>, and horizontally aligning with <code>\"left\"<\/code>, <code>\"center\"<\/code>, and <code>\"right\"<\/code>, there are 9 possible strings where each of the former strings are connected with the latter strings using a dash.<\/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;\">type<\/span> <span style=\"color: #267F99;\">VerticalAlignment<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"top\"<\/span> | <span style=\"color: #a31515;\">\"middle\"<\/span> | <span style=\"color: #a31515;\">\"bottom\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">HorizontalAlignment<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"left\"<\/span> | <span style=\"color: #a31515;\">\"center\"<\/span> | <span style=\"color: #a31515;\">\"right\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ Takes<\/span>\r\n<span style=\"color: #148A14;\">\/\/   | \"top-left\"    | \"top-center\"    | \"top-right\"<\/span>\r\n<span style=\"color: #148A14;\">\/\/   | \"middle-left\" | \"middle-center\" | \"middle-right\"<\/span>\r\n<span style=\"color: #148A14;\">\/\/   | \"bottom-left\" | \"bottom-center\" | \"bottom-right\"<\/span>\r\n<span style=\"color: #0000ff;\">declare<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-s1\">setAlignment<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">value<\/span>: `${<span style=\"color: #267F99;\">VerticalAlignment<\/span><span class=\"pl-kos\">}<\/span><span class=\"pl-c1\">-<\/span>${<span style=\"color: #267F99;\">HorizontalAlignment<\/span><span class=\"pl-kos\">}<\/span>`<span class=\"pl-kos\">)<\/span>: <span class=\"pl-smi\"><span style=\"color: #0000ff;\">void<\/span><\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-en\">setAlignment<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"top-left\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>   <span style=\"color: #148A14;\">\/\/ works!<\/span>\r\n<span class=\"pl-en\">setAlignment<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"top-middel\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span> <span style=\"color: #148A14;\">\/\/ error!<\/span>\r\n<span class=\"pl-en\">setAlignment<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"top-pot\"<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>    <span style=\"color: #148A14;\">\/\/ error! but good doughnuts if you're ever in Seattle<\/span><\/pre>\n<\/div>\n<p>While there are <strong>lots<\/strong> of examples of this sort of API in the wild, this is still a bit of a toy example since we could write these out manually. In fact, for 9 strings, this is likely fine; but when you need a ton of strings, you should consider automatically generating them ahead of time to save work on every type-check (or just use <code>string<\/code>, which will be much simpler to comprehend).<\/p>\n<p>Some of the real value comes from dynamically creating new string literals. For example, imagine a <code>makeWatchedObject<\/code> API that takes an object and produces a mostly identical object, but with a new <code>on<\/code> method to detect for changes to the properties.<\/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;\">let<\/span> <span class=\"pl-s1\">person<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-en\">makeWatchedObject<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">firstName<\/span>: <span style=\"color: #a31515;\">\"Homer\"<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-c1\">age<\/span>: <span style=\"color: #09885A;\">42<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #148A14;\">\/\/ give-or-take<\/span>\r\n    <span class=\"pl-c1\">location<\/span>: <span style=\"color: #a31515;\">\"Springfield\"<\/span><span class=\"pl-kos\">,<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span class=\"pl-s1\">person<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">on<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"firstNameChanged\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/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;\">`firstName was changed!`<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>Notice that <code>on<\/code> listens on the event <code>\"firstNameChanged\"<\/code>, not just <code>\"firstName\"<\/code>. How would we type this?<\/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;\">type<\/span> <span style=\"color: #267F99;\">PropEventSource<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">on<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">eventName<\/span>: `${<span style=\"color: #0000ff;\">string<\/span> &amp; <span style=\"color: #0000ff;\">keyof<\/span> <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">}<\/span><span style=\"color: #267F99;\">Changed<\/span>`<span class=\"pl-kos\">,<\/span> <span class=\"pl-s1\">callback<\/span>: <span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-smi\"><span style=\"color: #0000ff;\">void<\/span><\/span><span class=\"pl-kos\">)<\/span>: <span class=\"pl-smi\"><span style=\"color: #0000ff;\">void<\/span><\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/\/ Create a \"watched object\" with an 'on' method<\/span>\r\n<span style=\"color: #148A14;\">\/\/\/ so that you can watch for changes to properties.<\/span>\r\n<span style=\"color: #0000ff;\">declare<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-s1\">makeWatchedObject<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">obj<\/span>: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #267F99;\">T<\/span> &amp; <span style=\"color: #267F99;\">PropEventSource<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>With this, we can build something that errors when we give the wrong property!<\/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;\">\/\/ error!<\/span>\r\n<span class=\"pl-s1\">person<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">on<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"firstName\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ error!<\/span>\r\n<span class=\"pl-s1\">person<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">on<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"frstNameChanged\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>We can also do something special in template literal types: we can <em>infer<\/em> from substitution positions. We can make our last example generic to infer from parts of the <code>eventName<\/code> string to figure out the associated property.<\/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;\">type<\/span> <span style=\"color: #267F99;\">PropEventSource<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">on<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">K<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #0000ff;\">string<\/span> &amp; <span style=\"color: #0000ff;\">keyof<\/span> <span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span>\r\n        <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">eventName<\/span>: `${<span style=\"color: #267F99;\">K<\/span><span class=\"pl-kos\">}<\/span><span style=\"color: #267F99;\">Changed<\/span>`<span class=\"pl-kos\">,<\/span> <span class=\"pl-s1\">callback<\/span>: <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">newValue<\/span>: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-smi\"><span style=\"color: #0000ff;\">void<\/span><\/span> <span class=\"pl-kos\">)<\/span>: <span class=\"pl-smi\"><span style=\"color: #0000ff;\">void<\/span><\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">declare<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-s1\">makeWatchedObject<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">obj<\/span>: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #267F99;\">T<\/span> &amp; <span style=\"color: #267F99;\">PropEventSource<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">person<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-en\">makeWatchedObject<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">firstName<\/span>: <span style=\"color: #a31515;\">\"Homer\"<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-c1\">age<\/span>: <span style=\"color: #09885A;\">42<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-c1\">location<\/span>: <span style=\"color: #a31515;\">\"Springfield\"<\/span><span class=\"pl-kos\">,<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ works! 'newName' is typed as 'string'<\/span>\r\n<span class=\"pl-s1\">person<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">on<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"firstNameChanged\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-s1\">newName<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ 'newName' has the type of 'firstName'<\/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;\">`new name is <span class=\"pl-s1\"><span class=\"pl-kos\">${<\/span>newName<span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toUpperCase<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/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><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ works! 'newAge' is typed as 'number'<\/span>\r\n<span class=\"pl-s1\">person<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">on<\/span><span class=\"pl-kos\">(<\/span><span style=\"color: #a31515;\">\"ageChanged\"<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-s1\">newAge<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">newAge<\/span> <span class=\"pl-c1\">&lt;<\/span> <span style=\"color: #09885A;\">0<\/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;\">\"warning! negative age\"<\/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><span class=\"pl-kos\">)<\/span><\/pre>\n<\/div>\n<p>Here we made <code>on<\/code> into a generic method. When a user calls with the string <code>\"firstNameChanged'<\/code>, TypeScript will try to infer the right type for <code>K<\/code>. To do that, it will match <code>K<\/code> against the content prior to <code>\"Changed\"<\/code> and infer the string <code>\"firstName\"<\/code>. Once TypeScript figures that out, the <code>on<\/code> method can fetch the type of <code>firstName<\/code> on the original object, which is <code>string<\/code> in this case. Similarly, when we call with <code>\"ageChanged\"<\/code>, it finds the type for the property <code>age<\/code> which is `number).<\/p>\n<p>Inference can be combined in different ways, often to deconstruct strings, and reconstruct them in different ways. In fact, to help with modifying these string literal types, we&#8217;ve added a few new utilities for modifying casing in letters (i.e. converting to lowercase and uppercase characters).<\/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;\">type<\/span> <span style=\"color: #267F99;\">EnthusiasticGreeting<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> `${<span class=\"pl-smi\">uppercase<\/span> <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">}<\/span>`\r\n\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">HELLO<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">EnthusiasticGreeting<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #a31515;\">\"hello\"<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/ same as<\/span>\r\n<span style=\"color: #148A14;\">\/\/   type HELLO = \"HELLO\";<\/span><\/pre>\n<\/div>\n<p>Currently, these utilities are type operators named <code>uppercase<\/code>, <code>lowercase<\/code>, <code>capitalize<\/code>, and <code>uncapitalize<\/code>. The first two transform every character in a string, and the latter two transform only the first character in a string. They can only be used in template substitution positions, and in 4.1&#8217;s final release, they will likely be switched over to type aliases named <code>Uppercase<\/code>, <code>Lowercase<\/code>, <code>Capitalize<\/code> and <code>Uncapitalize<\/code>.<\/p>\n<p>For more details, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/40336\">see the original pull request<\/a> and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/40580\">the in-progress pull request to switch to type alias helpers<\/a>.<\/p>\n<h2 id=\"key-remapping-mapped-types\">Key Remapping in Mapped Types<\/h2>\n<p>Just as a refresher, a mapped type can create new object types based on arbitrary keys<\/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;\">type<\/span> <span style=\"color: #267F99;\">Options<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span> <span style=\"color: #0000ff;\">in<\/span> <span style=\"color: #a31515;\">\"noImplicitAny\"<\/span> | <span style=\"color: #a31515;\">\"strictNullChecks\"<\/span> | <span style=\"color: #a31515;\">\"strictFunctionTypes\"<\/span><span class=\"pl-kos\">]<\/span>?: <span style=\"color: #0000ff;\">boolean<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/ same as<\/span>\r\n<span style=\"color: #148A14;\">\/\/   type Options = {<\/span>\r\n<span style=\"color: #148A14;\">\/\/       noImplicitAny?: boolean,<\/span>\r\n<span style=\"color: #148A14;\">\/\/       strictNullChecks?: boolean,<\/span>\r\n<span style=\"color: #148A14;\">\/\/       strictFunctionTypes?: boolean<\/span>\r\n<span style=\"color: #148A14;\">\/\/   };<\/span><\/pre>\n<\/div>\n<p>or new object types based on other object 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;\">\/\/\/ 'Partial&lt;T&gt;' is the same as 'T', but with each property marked optional.<\/span>\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">Partial<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span> <span style=\"color: #0000ff;\">in<\/span> <span style=\"color: #0000ff;\">keyof<\/span> <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">]<\/span>?: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span><span class=\"pl-kos\">]<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>Until now, mapped types could only produce new object types with keys that you provided them; however, lots of the time you want to be able to create new keys, or filter out keys, based on the inputs.<\/p>\n<p>That&#8217;s why TypeScript 4.1 allows you to re-map keys in mapped types with a new <code>as<\/code> clause.<\/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;\">type<\/span> <span style=\"color: #267F99;\">MappedTypeWithNewKeys<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span> <span style=\"color: #0000ff;\">in<\/span> <span style=\"color: #0000ff;\">keyof<\/span> <span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">as<\/span> <span style=\"color: #267F99;\">NewKeyType<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span><span class=\"pl-kos\">]<\/span>\r\n    <span style=\"color: #148A14;\">\/\/            ^^^^^^^^^^^^^<\/span>\r\n    <span style=\"color: #148A14;\">\/\/            This is the new syntax!<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>With this new <code>as<\/code> clause, you can leverage features like template literal types to easily create property names based off of old ones.<\/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;\">type<\/span> <span style=\"color: #267F99;\">Getters<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span> <span style=\"color: #0000ff;\">in<\/span> <span style=\"color: #0000ff;\">keyof<\/span> <span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">as<\/span> <span style=\"color: #a31515;\">`get<span class=\"pl-s1\"><span class=\"pl-kos\">${<\/span>capitalize <span style=\"color: #267F99;\">K<\/span><span class=\"pl-kos\">}<\/span><\/span>`<\/span><span class=\"pl-kos\">]<\/span>: <span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span><span class=\"pl-kos\">]<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">interface<\/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><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-c1\">age<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-c1\">location<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">LazyPerson<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">Getters<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Person<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>and you can even filter out keys by producing <code>never<\/code>. That means you don&#8217;t have to use an extra <code>Omit<\/code> helper type in some cases.<\/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;\">type<\/span> <span style=\"color: #267F99;\">RemoveKindField<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span> <span style=\"color: #0000ff;\">in<\/span> <span style=\"color: #0000ff;\">keyof<\/span> <span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">as<\/span> <span style=\"color: #267F99;\">Exclude<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">K<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #a31515;\">\"kind\"<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">K<\/span><span class=\"pl-kos\">]<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">interface<\/span> <span style=\"color: #267F99;\">Circle<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">kind<\/span>: <span style=\"color: #a31515;\">\"circle\"<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-c1\">radius<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">type<\/span> <span style=\"color: #267F99;\">KindlessCircle<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">RemoveKindField<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Circle<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #148A14;\">\/\/ same as<\/span>\r\n<span style=\"color: #148A14;\">\/\/   type KindlessCircle = {<\/span>\r\n<span style=\"color: #148A14;\">\/\/       radius: number;<\/span>\r\n<span style=\"color: #148A14;\">\/\/   };<\/span><\/pre>\n<\/div>\n<p>For more information, take a look at <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/40336\">the original pull request over on GitHub<\/a>.<\/p>\n<h2 id=\"recursive-conditional-types\">Recursive Conditional Types<\/h2>\n<p>In JavaScript it&#8217;s fairly common to see functions that can flatten and build up container types at arbitrary levels. For example, consider the <code>.then()<\/code> method on instances of <code>Promise<\/code>. <code>.then(...)<\/code> unwraps each promise until it finds a value that&#8217;s not &#8220;promise-like&#8221;, and passes that value to a callback. There&#8217;s also a relatively new <code>flat<\/code> method on <code>Array<\/code>s that can take a depth of how deep to flatten.<\/p>\n<p>Expressing this in TypeScript&#8217;s type system was, for all practical intents and purposes, not possible. While there were hacks to achieve this, the types ended up looking very unreasonable.<\/p>\n<p>That&#8217;s why TypeScript 4.1 eases some restrictions on conditional types &#8211; so that they can model these patterns. In TypeScript 4.1, conditional types can now immediately reference themselves within their branches, making it easier to write recursive type aliases.<\/p>\n<p>For example, if we wanted to write a type to get the element types of nested arrays, we could write the following <code>deepFlatten<\/code> 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;\">type<\/span> <span style=\"color: #267F99;\">ElementType<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span>\r\n    <span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #267F99;\">ReadonlyArray<\/span><span class=\"pl-kos\">&lt;<\/span><span class=\"pl-smi\">infer<\/span> <span style=\"color: #267F99;\">U<\/span><span class=\"pl-kos\">&gt;<\/span> ? <span style=\"color: #267F99;\">ElementType<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">U<\/span><span class=\"pl-kos\">&gt;<\/span> : <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">deepFlatten<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span class=\"pl-smi\">readonly<\/span> <span class=\"pl-s1\">unknown<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-c1\">&gt;<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">x<\/span>: <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #267F99;\">ElementType<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">]<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">throw<\/span> <span style=\"color: #a31515;\">\"not implemented\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ All of these return the type 'number[]':<\/span>\r\n<span class=\"pl-en\">deepFlatten<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #09885A;\">1<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #09885A;\">2<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #09885A;\">3<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-en\">deepFlatten<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #09885A;\">1<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-kos\">[<\/span><span style=\"color: #09885A;\">2<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #09885A;\">3<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-en\">deepFlatten<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #09885A;\">1<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #09885A;\">2<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">,<\/span> <span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #09885A;\">3<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">]<\/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>Similarly, in TypeScript 4.1 we can write an <code>Awaited<\/code> type to deeply unwrap <code>Promise<\/code>s.<\/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;\">type<\/span> <span style=\"color: #267F99;\">Awaited<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-c1\">&gt;<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #267F99;\">T<\/span> <span style=\"color: #0000ff;\">extends<\/span> <span style=\"color: #267F99;\">PromiseLike<\/span><span class=\"pl-kos\">&lt;<\/span><span class=\"pl-smi\">infer<\/span> <span style=\"color: #267F99;\">U<\/span><span class=\"pl-kos\">&gt;<\/span> ? <span style=\"color: #267F99;\">Awaited<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">U<\/span><span class=\"pl-kos\">&gt;<\/span> : <span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/\/ Like `promise.then(...)`, but more accurate in types.<\/span>\r\n<span style=\"color: #0000ff;\">declare<\/span> <span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-s1\">customThen<\/span><span class=\"pl-c1\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">,<\/span> <span style=\"color: #267F99;\">U<\/span><span class=\"pl-c1\">&gt;<\/span><span class=\"pl-kos\">(<\/span>\r\n    <span class=\"pl-s1\">p<\/span>: <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span class=\"pl-s1\">onFulfilled<\/span>: <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">value<\/span>: <span style=\"color: #267F99;\">Awaited<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">T<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span style=\"color: #267F99;\">U<\/span>\r\n<span class=\"pl-kos\">)<\/span>: <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">Awaited<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #267F99;\">U<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>Keep in mind that while these recursive types are powerful, but they should be used responsibly and sparingly.<\/p>\n<p>First off, these types can do a lot of work which means that they can increase type-checking time. Trying to model numbers in the Collatz conjecture or Fibonacci sequence might be fun, but don&#8217;t ship that in <code>.d.ts<\/code> files on npm.<\/p>\n<p>But apart from being computationally intensive, these types can hit an internal recursion depth limit on sufficiently-complex inputs. When that recursion limit is hit, that results in a compile-time error. In general, it&#8217;s better not to use these types at all than to write something that fails on more realistic examples.<\/p>\n<p>See more <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/40002\">at the implementation<\/a>.<\/p>\n<h2 id=\"no-unchecked-indexed-access\">Pedantic Index Signature Checks (<code>--noUncheckedIndexedAccess<\/code>)<\/h2>\n<p>TypeScript has a feature called <em>index signatures<\/em>. These signatures are a way to signal to the type system that users can access arbitrarily-named properties.<\/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;\">interface<\/span> <span style=\"color: #267F99;\">Options<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-c1\">path<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-c1\">permissions<\/span>: <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ Extra properties are caught by this index signature.<\/span>\r\n    <span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">propName<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">]<\/span>: <span style=\"color: #0000ff;\">string<\/span> | <span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">checkOptions<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">opts<\/span>: <span style=\"color: #267F99;\">Options<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-s1\">opts<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">path<\/span> <span style=\"color: #148A14;\">\/\/ string<\/span>\r\n    <span class=\"pl-s1\">opts<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">permissions<\/span> <span style=\"color: #148A14;\">\/\/ number<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ These are all allowed too!<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ They have the type 'string | number'.<\/span>\r\n    <span class=\"pl-s1\">opts<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">yadda<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toString<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-s1\">opts<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #a31515;\">\"foo bar baz\"<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toString<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-s1\">opts<\/span><span class=\"pl-kos\">[<\/span><span style=\"color: #267F99;\">Math<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">random<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toString<\/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>In the above example, <code>Options<\/code> has an index signature that says any accessed property that&#8217;s not already listed should have the type <code>string | number<\/code>. This is often convenient for optimistic code that assumes you know what you&#8217;re doing, but the truth is that most values in JavaScript do not support every potential property name. Most types will not, for example, have a value for a property key created by <code>Math.random()<\/code> like in the previous example. For many users, this behavior was undesirable, and felt like it wasn&#8217;t leveraging the full strict-checking of <code>--strictNullChecks<\/code>.<\/p>\n<p>That&#8217;s why TypeScript 4.1 ships with a new flag called <code>--noUncheckedIndexedAccess<\/code>. Under this new mode, every property access (like <code>foo.bar<\/code>) or indexed access (like <code>foo[\"bar\"]<\/code>) is considered potentially undefined. That means that in our last example, <code>opts.yadda<\/code> will have the type <code>string | number | undefined<\/code> as opposed to just <code>string | number<\/code>. If you need to access that property, you&#8217;ll either have to check for its existence first or use a non-null assertion operator (the postfix <code>!<\/code> character).<\/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;\">\/\/ Checking if it's really there first.<\/span>\r\n<span style=\"color: #0000ff;\">if<\/span> <span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">opts<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">yadda<\/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\">opts<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">yadda<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toString<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n\r\n\r\n<span style=\"color: #148A14;\">\/\/ Basically saying \"trust me I know what I'm doing\"<\/span>\r\n<span style=\"color: #148A14;\">\/\/ with the '!' non-null assertion operator.<\/span>\r\n<span class=\"pl-s1\">opts<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">yadda<\/span>!<span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toString<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>One consequence of using <code>--noUncheckedIndexedAccess<\/code> is that indexing into an array is also more strictly checked, even in a bounds-checked loop.<\/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;\">function<\/span> <span class=\"pl-en\">screamLines<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">strs<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ this will have issues<\/span>\r\n    <span style=\"color: #0000ff;\">for<\/span> <span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">i<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #09885A;\">0<\/span><span class=\"pl-kos\">;<\/span> <span class=\"pl-s1\">i<\/span> <span class=\"pl-c1\">&lt;<\/span> <span class=\"pl-s1\">strs<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">length<\/span><span class=\"pl-kos\">;<\/span> <span class=\"pl-s1\">i<\/span><span class=\"pl-c1\">++<\/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\">strs<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-s1\">i<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toUpperCase<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/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! Object is possibly 'undefined'.<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>If you don&#8217;t need the indexes, you can iterate over individual elements by using a <code>for<\/code>&#8211;<code>of<\/code> loop or a <code>forEach<\/code> call.<\/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;\">function<\/span> <span class=\"pl-en\">screamLines<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">strs<\/span>: <span style=\"color: #0000ff;\">string<\/span><span class=\"pl-kos\">[<\/span><span class=\"pl-kos\">]<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/ this works fine<\/span>\r\n    <span style=\"color: #0000ff;\">for<\/span> <span class=\"pl-kos\">(<\/span><span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">str<\/span> <span style=\"color: #0000ff;\">of<\/span> <span class=\"pl-s1\">strs<\/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\">str<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toUpperCase<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n\r\n    <span style=\"color: #148A14;\">\/\/ this works fine<\/span>\r\n    <span class=\"pl-s1\">strs<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">forEach<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">str<\/span> <span class=\"pl-c1\">=&gt;<\/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\">str<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-en\">toUpperCase<\/span><span class=\"pl-kos\">(<\/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-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>This flag can be handy for catching out-of-bounds errors, but might be noisy for a lot of code, so it is not automatically enabled by the <code>--strict<\/code> flag.<\/p>\n<p>You can learn more <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/39560\">at the implementing pull request<\/a>.<\/p>\n<h2 id=\"template-literal-types\"><code>paths<\/code> without <code>baseUrl<\/code><\/h2>\n<p>Using path-mapping is fairly common &#8211; often it&#8217;s to have nicer imports, often it&#8217;s to simulate monorepo linking behavior.<\/p>\n<p>Unfortunately, specifying <code>paths<\/code> to enable path-mapping required also specifying an option called <code>baseUrl<\/code>, which allows bare specifier paths to be reached relative to the <code>baseUrl<\/code> too. This also often caused poor paths to be used by auto-imports.<\/p>\n<p>In TypeScript 4.1, the <code>paths<\/code> option can be used without <code>baseUrl<\/code>. This helps avoid some of these issues.<\/p>\n<h2 id=\"checkjs-implies-allowjs\"><code>checkJs<\/code> Implies <code>allowJs<\/code><\/h2>\n<p>Previously if you were starting a checked JavaScript project, you had to set both <code>allowJs<\/code> and <code>checkJs<\/code>. This was a slightly annoying bit of friction in the experience, so <code>checkJs<\/code> now implies <code>allowJs<\/code> by default.<\/p>\n<p><a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/40275\">See more details at the pull request<\/a>.<\/p>\n<h2 id=\"jsx-factories\">React 17 JSX Factories<\/h2>\n<p>TypeScript 4.1 supports React 17&#8217;s upcoming <code>jsx<\/code> and <code>jsxs<\/code> factory functions through two new options for the <code>jsx<\/code> compiler option:<\/p>\n<ul>\n<li><code>react-jsx<\/code><\/li>\n<li><code>react-jsxdev<\/code><\/li>\n<\/ul>\n<p>These options are intended for production and development compiles respectively. Often, the options from one can extend from the other. For example, a <code>tsconfig.json<\/code> for production builds might look like the following:<\/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;\">\/\/ .\/src\/tsconfig.json<\/span>\r\n<span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #a31515;\">\"compilerOptions\"<\/span>: <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #a31515;\">\"module\"<\/span>: <span style=\"color: #a31515;\">\"esnext\"<\/span><span class=\"pl-kos\">,<\/span>\r\n        <span style=\"color: #a31515;\">\"target\"<\/span>: <span style=\"color: #a31515;\">\"es2015\"<\/span><span class=\"pl-kos\">,<\/span>\r\n        <span style=\"color: #a31515;\">\"jsx\"<\/span>: <span style=\"color: #a31515;\">\"react-jsx\"<\/span><span class=\"pl-kos\">,<\/span>\r\n        <span style=\"color: #a31515;\">\"strict\"<\/span>: <span style=\"color: #0000ff;\">true<\/span>\r\n    <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span style=\"color: #a31515;\">\"include\"<\/span>: <span class=\"pl-kos\">[<\/span>\r\n        <span style=\"color: #a31515;\">\".\/**\/*\"<\/span>\r\n    <span class=\"pl-kos\">]<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>and one for development builds might look like the following:<\/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;\">\/\/ .\/src\/tsconfig.dev.json<\/span>\r\n<span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #a31515;\">\"extends\"<\/span>: <span style=\"color: #a31515;\">\".\/tsconfig.json\"<\/span><span class=\"pl-kos\">,<\/span>\r\n    <span style=\"color: #a31515;\">\"compilerOptions\"<\/span>: <span class=\"pl-kos\">{<\/span>\r\n        <span style=\"color: #a31515;\">\"jsx\"<\/span>: <span style=\"color: #a31515;\">\"react-jsxdev\"<\/span>\r\n    <span class=\"pl-kos\">}<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>For more information, <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/39199\">check out the corresponding PR<\/a>.<\/p>\n<h2 id=\"jsdoc-see-tag\">Editor Support for the JSDoc <code>@see<\/code> Tag<\/h2>\n<p>The JSDoc tag <code>@see<\/code> tag now has better support in editors for TypeScript and JavaScript. This allows you to use functionality like go-to-definition in a dotted name following the tag. For example, going to definition on <code>first<\/code> or <code>C<\/code> in the JSDoc comment just works in the following example:<\/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;\">\/\/ <span class=\"pl-k\">@filename<\/span>: first.ts<\/span>\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #267F99;\">C<\/span> <span class=\"pl-kos\">{<\/span> <span class=\"pl-kos\">}<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ <span class=\"pl-k\">@filename<\/span>: main.ts<\/span>\r\n<span style=\"color: #0000ff;\">import<\/span> * <span style=\"color: #0000ff;\">as<\/span> <span class=\"pl-s1\">first<\/span> <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">'.\/first'<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/**<\/span>\r\n<span style=\"color: #148A14;\"> * <span class=\"pl-k\">@see<\/span> first.C<\/span>\r\n<span style=\"color: #148A14;\"> *\/<\/span>\r\n<span style=\"color: #0000ff;\">function<\/span> <span class=\"pl-en\">related<\/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>Thanks to frequent contributor <a href=\"https:\/\/github.com\/Kingwl\">Wenlu Wang<\/a> <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/pull\/39760\">for implementing this<\/a>!<\/p>\n<h2 id=\"breaking-changes\">Breaking Changes<\/h2>\n<h3><code>abstract<\/code> Members Can&#8217;t Be Marked <code>async<\/code><\/h3>\n<p>Members marked as <code>abstract<\/code> can no longer be marked as <code>async<\/code>. The fix here is to remove the <code>async<\/code> keyword, since callers are only concerned with the return type.<\/p>\n<h3><code>any<\/code>\/<code>unknown<\/code> Are Propagated in Falsy Positions<\/h3>\n<p>Previously, for an expression like <code>foo &amp;&amp; somethingElse<\/code>, the type of <code>foo<\/code> was <code>any<\/code> or <code>unknown<\/code>, the type of the whole that expression would be the type of <code>somethingElse<\/code>.<\/p>\n<p>For example, previously the type for <code>x<\/code> here was <code>{ someProp: string }<\/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;\">declare<\/span> <span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">foo<\/span>: <span style=\"color: #0000ff;\">unknown<\/span><span class=\"pl-kos\">;<\/span>\r\n<span style=\"color: #0000ff;\">declare<\/span> <span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">somethingElse<\/span>: <span class=\"pl-kos\">{<\/span> <span class=\"pl-c1\">someProp<\/span>: <span style=\"color: #0000ff;\">string<\/span> <span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">let<\/span> <span class=\"pl-s1\">x<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">foo<\/span> <span class=\"pl-c1\">&amp;&amp;<\/span> <span class=\"pl-s1\">somethingElse<\/span><span class=\"pl-kos\">;<\/span><\/pre>\n<\/div>\n<p>However, in TypeScript 4.1, we are more careful about how we determine this type. Since nothing is known about the type on the left side of the <code>&amp;&amp;<\/code>, we propagate <code>any<\/code> and <code>unknown<\/code> outward instead of the type on the right side.<\/p>\n<p>The most common pattern we saw of this tended to be when checking compatibility with <code>boolean<\/code>s, especially in predicate functions.<\/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;\">function<\/span> <span class=\"pl-en\">isThing<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">x<\/span>: <span style=\"color: #0000ff;\">any<\/span><span class=\"pl-kos\">)<\/span>: <span style=\"color: #0000ff;\">boolean<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">return<\/span> <span class=\"pl-s1\">x<\/span> <span class=\"pl-c1\">&amp;&amp;<\/span> <span style=\"color: #0000ff;\">typeof<\/span> <span class=\"pl-s1\">x<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">'object'<\/span> <span class=\"pl-c1\">&amp;&amp;<\/span> <span class=\"pl-s1\">x<\/span><span class=\"pl-kos\">.<\/span><span class=\"pl-c1\">blah<\/span> <span class=\"pl-c1\">===<\/span> <span style=\"color: #a31515;\">'foo'<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>Often the appropriate fix is to switch from <code>foo &amp;&amp; someExpression<\/code> to <code>!!foo &amp;&amp; someExpression<\/code>.<\/p>\n<h3><code>--declaration<\/code> and <code>--outFile<\/code> Requires a Package Name Root<\/h3>\n<p>When you have a project which uses both <code>outFile<\/code> plus <code>declaration<\/code> to emit a single <code>.js<\/code> file for your project, alongside a corresponding <code>.d.ts<\/code> file, that declaration file would usually require some sort of post-processing of the module identifiers to make sense to external consumers. For example, a project like<\/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;\">\/\/ <span class=\"pl-k\">@filename<\/span>: projectRoot\/index.ts<\/span>\r\n<span style=\"color: #0000ff;\">export<\/span> * <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\".\/nested\/base\"<\/span><span class=\"pl-kos\">;<\/span>\r\n\r\n<span style=\"color: #148A14;\">\/\/ <span class=\"pl-k\">@filename<\/span>: projectRoot\/nested\/base.ts<\/span>\r\n<span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">a<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"123\"<\/span><\/pre>\n<\/div>\n<p>Would produce a <code>.d.ts<\/code> file that looks like the following:<\/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;\">declare<\/span> module <span style=\"color: #a31515;\">\"nested\/base\"<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">a<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"123\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n<span style=\"color: #0000ff;\">declare<\/span> module <span style=\"color: #a31515;\">\"index\"<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">export<\/span> * <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\"nested\/base\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>Which is technically accurate, but not that useful. TypeScript 4.1 requires <code>bundledPackageName<\/code> to be specified when a single <code>.d.ts<\/code> file is requested to be produced.<\/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;\">declare<\/span> module <span style=\"color: #a31515;\">\"hello\/nested\/base\"<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">export<\/span> <span style=\"color: #0000ff;\">const<\/span> <span class=\"pl-s1\">a<\/span> <span class=\"pl-c1\">=<\/span> <span style=\"color: #a31515;\">\"123\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span>\r\n<span style=\"color: #0000ff;\">declare<\/span> module <span style=\"color: #a31515;\">\"hello\"<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #0000ff;\">export<\/span> * <span style=\"color: #0000ff;\">from<\/span> <span style=\"color: #a31515;\">\"hello\/nested\/base\"<\/span><span class=\"pl-kos\">;<\/span>\r\n<span class=\"pl-kos\">}<\/span><\/pre>\n<\/div>\n<p>Without this option, you may receive an error like<\/p>\n<pre><code>The `bundledPackageName` option must be provided when using outFile and node module resolution with declaration emit.\r\n<\/code><\/pre>\n<h3><code>resolve<\/code>&#8216;s Parameters Are No Longer Optional in <code>Promise<\/code>s<\/h3>\n<p>When writing code like the following<\/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;\">new<\/span> <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">resolve<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span class=\"pl-en\">doSomethingAsync<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-en\">doSomething<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span class=\"pl-en\">resolve<\/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-kos\">)<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><\/pre>\n<\/div>\n<p>You may get an error like the following:<\/p>\n<pre><code>  resolve()\r\n  ~~~~~~~~~\r\nerror TS2554: Expected 1 arguments, but got 0.\r\n  An argument for 'value' was not provided.\r\n<\/code><\/pre>\n<p>This is because <code>resolve<\/code> no longer has an optional paramter, so by default, it must now be passed a value. Often this catches legitimate bugs with using <code>Promise<\/code>s. The typical fix is to pass it the correct argument, and sometimes to add an explicit type argument.<\/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;\">new<\/span> <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span style=\"color: #0000ff;\">number<\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">resolve<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/     ^^^^^^^^<\/span>\r\n    <span class=\"pl-en\">doSomethingAsync<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">value<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-en\">doSomething<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span class=\"pl-en\">resolve<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">value<\/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><span class=\"pl-kos\">)<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><\/pre>\n<\/div>\n<p>However, sometimes <code>resolve()<\/code> realy does need to be called without an argument. In these cases, we can give <code>Promise<\/code> an explicit <code>void<\/code> generic type argument (i.e. write it out as <code>Promise&lt;void&gt;<\/code>). This leverages new functionality in TypeScript 4.1 where a potentially-<code>void<\/code> trailing parameter can become optional.<\/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;\">new<\/span> <span style=\"color: #267F99;\">Promise<\/span><span class=\"pl-kos\">&lt;<\/span><span class=\"pl-smi\"><span style=\"color: #0000ff;\">void<\/span><\/span><span class=\"pl-kos\">&gt;<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-s1\">resolve<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n    <span style=\"color: #148A14;\">\/\/     ^^^^^^<\/span>\r\n    <span class=\"pl-en\">doSomethingAsync<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span> <span class=\"pl-c1\">=&gt;<\/span> <span class=\"pl-kos\">{<\/span>\r\n        <span class=\"pl-en\">doSomething<\/span><span class=\"pl-kos\">(<\/span><span class=\"pl-kos\">)<\/span><span class=\"pl-kos\">;<\/span>\r\n        <span class=\"pl-en\">resolve<\/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-kos\">)<\/span>\r\n<span class=\"pl-kos\">}<\/span><span class=\"pl-kos\">)<\/span><\/pre>\n<\/div>\n<p>TypeScript 4.1 ships with a quick fix to help fix this break.<\/p>\n<h2>What&#8217;s Next?<\/h2>\n<p>As always, we&#8217;ll be working on smoothing out the experience until 4.1 comes out. We&#8217;d love to hear what your thoughts are we finalize our Release Candidate next month, so please give TypeScript 4.1 and <a href=\"https:\/\/github.com\/microsoft\/TypeScript\/issues\/new\/\">let us know if you run into anything<\/a>!<\/p>\n<p>Happy Hacking!<\/p>\n<p>&#8211; Daniel Rosenwasser and the TypeScript Team<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re announcing the availability of TypeScript 4.1 Beta! To get started using the beta, you can get it through NuGet, or use npm with the following command: npm install typescript@beta You can also get editor support by Downloading for Visual Studio 2019\/2017 Following directions for Visual Studio Code and Sublime Text. For this release, [&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-2766","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 4.1 Beta! To get started using the beta, you can get it through NuGet, or use npm with the following command: npm install typescript@beta You can also get editor support by Downloading for Visual Studio 2019\/2017 Following directions for Visual Studio Code and Sublime Text. For this release, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/2766","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=2766"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/posts\/2766\/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=2766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/categories?post=2766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/typescript\/wp-json\/wp\/v2\/tags?post=2766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}