{"id":6443,"date":"2025-07-03T09:47:14","date_gmt":"2025-07-03T14:47:14","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=6443"},"modified":"2025-07-03T09:47:15","modified_gmt":"2025-07-03T14:47:15","slug":"satisfies-in-typescript","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/satisfies-in-typescript\/","title":{"rendered":"Satisfies in TypeScript"},"content":{"rendered":"\n<p>This is a post about one of TypeScript&#8217;s less common features: the&nbsp;<code>satisfies<\/code>&nbsp;keyword. It&#8217;s occasionally incredibly useful, and knowing how to properly wield it is a valuable trick to have up your sleeve. Let&#8217;s take a look!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"a-quick-intro-on-structural-typing\">A quick intro on structural typing<\/h2>\n\n\n\n<p>In a nutshell, structural typing means that TypeScript cares only about the&nbsp;<em>structure<\/em>&nbsp;of your values, not the types they were declared with. That means the following code contains no errors:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">class<\/span> Thing1 {\n  name: <span class=\"hljs-built_in\">string<\/span> = <span class=\"hljs-string\">\"\"<\/span>;\n}\n\n<span class=\"hljs-keyword\">class<\/span> Thing2 {\n  name: <span class=\"hljs-built_in\">string<\/span> = <span class=\"hljs-string\">\"\"<\/span>;\n}\n\n<span class=\"hljs-keyword\">let<\/span> thing1: Thing1 = <span class=\"hljs-keyword\">new<\/span> Thing1();\n<span class=\"hljs-keyword\">let<\/span> thing2: Thing1 = <span class=\"hljs-keyword\">new<\/span> Thing2();\n<span class=\"hljs-keyword\">let<\/span> thing3: Thing1 = { name: <span class=\"hljs-string\">\"\"<\/span> };<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Types are essentially contracts, and TypeScript cares only that you satisfy the contract with something that has what the original type specified.<\/p>\n\n\n\n<p>Interestingly, this also means you can supply extraneous, superfluous &#8220;stuff&#8221; when satisfying types: the following also has no errors.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">const<\/span> val = {\n  name: <span class=\"hljs-string\">\"\"<\/span>,\n  xyz: <span class=\"hljs-number\">12<\/span>,\n};\n\n<span class=\"hljs-keyword\">let<\/span> thing4: Thing1 = val;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The&nbsp;<code>Thing1<\/code>&nbsp;type only calls for a <code>name<\/code> property that&#8217;s a <code>string<\/code>. If you also specify <em>other<\/em> properties, TypeScript is (usually) OK with it. This might seem surprising coming from other languages, but it&#8217;s a pragmatic tradeoff given that TypeScript&#8217;s primary purpose is to provide some manner of type safety to a completely untyped programming language: JavaScript.<\/p>\n\n\n\n<p>I said <em>usually<\/em> above because occasionally TypeScript will be a bit stricter about not allowing &#8220;extra&#8221; values like we saw above. In particular, when assigning an object literal to a variable that&#8217;s declared with a type, TypeScript will require a strict matching.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">let<\/span> thing4: Thing1 = val;\n\n<span class=\"hljs-keyword\">const<\/span> val2: Thing1 = {\n  name: <span class=\"hljs-string\">\"\"<\/span>,\n  xyz: <span class=\"hljs-number\">12<\/span>,\n  <span class=\"hljs-comment\">\/\/ Error: Object literal may only specify known properties, and 'xyz' does not exist in type 'Thing1'<\/span>\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This is called &#8220;excess property checking.&#8221; It happens when assigning an object literal to a variable with a declared type, like we just saw, and also when passing an object literal to a function parameter that has a declared type.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-satisfies-keyword\">The <code>satisfies<\/code> keyword<\/h2>\n\n\n\n<p>To provide the most simplistic example of using <code>satisfies<\/code>, let&#8217;s go back to this code<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">const<\/span> val3 = {\n  name: <span class=\"hljs-string\">\"\"<\/span>,\n  xyz: <span class=\"hljs-number\">12<\/span>,\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Right now <code>val3<\/code> has the inferred type<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\">{\n  name: <span class=\"hljs-built_in\">string<\/span>;\n  xyz: <span class=\"hljs-built_in\">number<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If we wanted, we could write this code like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">const<\/span> val3 = {\n  name: <span class=\"hljs-string\">\"\"<\/span>,\n  xyz: <span class=\"hljs-number\">12<\/span>,\n  <span class=\"hljs-comment\">\/\/ Error: Object literal may only specify known properties, and 'xyz' does not exist in type 'Thing1'<\/span>\n} satisfies Thing1;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That produced the same error we saw before, and the same error we&nbsp;<em>would have<\/em>&nbsp;gotten if we had declared <code>val3<\/code> as&nbsp;<code>Thing1<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> val3: Thing1 = {\n  <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"\"<\/span>,\n  <span class=\"hljs-attr\">xyz<\/span>: <span class=\"hljs-number\">12<\/span>,\n  <span class=\"hljs-comment\">\/\/ Error: Object literal may only specify known properties, and 'xyz' does not exist in type 'Thing1'<\/span>\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"learn-more\">The <code>satisfies<\/code> keyword allows you to assert that a certain value &#8220;satisfies&#8221; a given type, while <em>preventing<\/em> a wider type from being inferred.<\/p>\n\n\n\n<p>Bear with me.<\/p>\n\n\n\n<p>You&#8217;re probably thinking that this is completely pointless, since we can just move&nbsp;<code>Thing1<\/code>&nbsp;up into a proper type declaration, and even save a few keystrokes while doing so!<\/p>\n\n\n\n<p>But not all situations lend themselves to this solution.<\/p>\n\n\n\n<p>Let&#8217;s take a look at a slightly more complex, more realistic example.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"satisfies-in-the-wild\">The <code>satisfies<\/code> Keyword in the Wild<\/h2>\n\n\n\n<p>This is a situation I actually ran into. I&#8217;ll do my best to simplify it, while keeping the realistic parts.<\/p>\n\n\n\n<p>Imagine we&#8217;re writing an inventory management system. We have an inventory item type.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">type<\/span> InventoryItem = {\n  sku: <span class=\"hljs-built_in\">string<\/span>;\n  description: <span class=\"hljs-built_in\">string<\/span>;\n  originCode?: <span class=\"hljs-built_in\">string<\/span>;\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Maybe we have some external backend systems we need to fetch data from.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-keyword\">type<\/span> BackendResponse = {\n  item_sku: <span class=\"hljs-built_in\">string<\/span>;\n  item_description: <span class=\"hljs-built_in\">string<\/span>;\n  item_metadata: Record&lt;<span class=\"hljs-built_in\">string<\/span>, <span class=\"hljs-built_in\">string<\/span>&gt;;\n  item_origin_code: <span class=\"hljs-built_in\">string<\/span>;\n};\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getBackendResponse<\/span>(<span class=\"hljs-params\"><\/span>): <span class=\"hljs-title\">BackendResponse<\/span>&#91;] <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> &#91;];\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The&nbsp;<code>getBackendResponse<\/code>&nbsp;function is hard coded to return an empty array, but just pretend it makes a request and returns actual data. Then pretend we want to take that data and actually insert it. We have a function to do the inserting; we&#8217;re only interested in the types though, so we&#8217;ll leave the implementation empty<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">insertInventoryItems<\/span>(<span class=\"hljs-params\">items: InventoryItem&#91;]<\/span>) <\/span>{}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Let&#8217;s put things together. Fetch some items from our external system, manipulate them into the proper structure for our own&nbsp;<code>InventoryItem<\/code>&nbsp;type, and then call our&nbsp;<code>insertInventoryItems<\/code>&nbsp;function<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">main<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> backendItems = getBackendResponse();\n  insertInventoryItems(\n    backendItems.map(<span class=\"hljs-function\"><span class=\"hljs-params\">item<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">return<\/span> {\n        <span class=\"hljs-attr\">sku<\/span>: item.item_sku,\n        <span class=\"hljs-attr\">description<\/span>: item.item_description,\n        <span class=\"hljs-attr\">originCodeXXXXX<\/span>: item.item_origin_code,\n      };\n    })\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Unfortunately, <strong>this code has no errors<\/strong>, even though we completely fat-fingered the <code>originCode<\/code> property. <\/p>\n\n\n\n<p>You already know that TypeScript will allow you to provide &#8220;extra&#8221; properties in places where excess property checking doesn&#8217;t exist, but you may be wondering why it&#8217;s not an error that we completely&nbsp;<em>left off<\/em>&nbsp;the real&nbsp;<code>originCode<\/code>&nbsp;property. The reason is that this is an optional property! That makes it all the more important that we disallow excess cruft.<\/p>\n\n\n\n<p>You might be thinking that we can just restructure our code so that excess property checking is in place, and we certainly could do that<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">main<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> backendItems = getBackendResponse();\n  insertInventoryItems(\n    backendItems.map(<span class=\"hljs-function\"><span class=\"hljs-params\">item<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> result: InventoryItem = {\n        sku: item.item_sku,\n        description: item.item_description,\n        originCodeXXXXX: item.item_origin_code,\n        <span class=\"hljs-comment\">\/\/ Error: Object literal may only specify known properties, but 'originCodeXXXXX'<\/span>\n        <span class=\"hljs-comment\">\/\/ does not exist in type 'InventoryItem'. Did you mean to write 'originCode'<\/span>\n      };\n      <span class=\"hljs-keyword\">return<\/span> result;\n    })\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This works and produces the error we want to see. But it&#8217;s just a byproduct of the (frankly weird) way we chose to write it, and this protection would disappear if anyone were to come along, see this weird, pointless intermediate variable declaration, and &#8220;helpfully&#8221; refactor the code to just immediately return the object literal like we just had.<\/p>\n\n\n\n<p>The better solution is to use <code>satisfies<\/code> to prevent the unwanted widening; that&#8217;s why it exists!<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">main<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> backendItems = getBackendResponse();\n  insertInventoryItems(\n    backendItems.map(<span class=\"hljs-function\"><span class=\"hljs-params\">item<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">return<\/span> {\n        sku: item.item_sku,\n        description: item.item_description,\n        originCodeXXXXX: item.item_origin_code,\n        <span class=\"hljs-comment\">\/\/ Error: Object literal may only specify known properties, but 'originCodeXXXXX'<\/span>\n        <span class=\"hljs-comment\">\/\/ does not exist in type 'InventoryItem'. Did you mean to write 'originCode'<\/span>\n      } satisfies InventoryItem;\n    })\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now we&#8217;re back to the more idiomatic code we started with, with the same strict checks we&#8217;re looking for.<\/p>\n\n\n\n<p>Before we wrap up, let&#8217;s briefly consider this alternative you might be wondering about<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">main<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> backendItems = getBackendResponse();\n  insertInventoryItems(\n    backendItems.map(<span class=\"hljs-function\"><span class=\"hljs-params\">item<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">return<\/span> {\n        sku: item.item_sku,\n        description: item.item_description,\n        originCodeXXXXX: item.item_origin_code,\n      } <span class=\"hljs-keyword\">as<\/span> InventoryItem;\n    })\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This produces no errors at all. The <code>as<\/code> keyword is a typecast. It&#8217;s something to avoid; it essentially allows you to &#8220;lie&#8221; to the type checker and <em>assert<\/em> that a given expression matches a given type. In this case, the cast pointless because this object already matches the <code>InventoryItem<\/code> type. It has a sku, and a description. It also has some extra &#8220;stuff&#8221; but TypeScript doesn&#8217;t really mind. It&#8217;s the <code>satisfies<\/code> keyword which additionally forces TypeScript to also <em>not<\/em> allow a wider type, and therefor <em>start<\/em> minding about extra properties.<\/p>\n\n\n\n<p>For completeness, this version of the casting code actually does fail<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">main3<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> backendItems = getBackendResponse();\n  insertInventoryItems(\n    backendItems.map(<span class=\"hljs-function\"><span class=\"hljs-params\">item<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">return<\/span> {\n        sku: item.item_sku,\n        descriptionXXX: item.item_description,\n        <span class=\"hljs-comment\">\/\/ Error: Conversion of type '{ sku: string; description<span class=\"hljs-doctag\">XXX:<\/span> string; originCodeXX<span class=\"hljs-doctag\">XXX:<\/span> string; }' to type<\/span>\n        <span class=\"hljs-comment\">\/\/ 'InventoryItem' may be a mistake because neither type sufficiently overlaps with the other. If this<\/span>\n        <span class=\"hljs-comment\">\/\/ was intentional, convert the expression to 'unknown' first. Property 'description' is missing in type<\/span>\n        <span class=\"hljs-comment\">\/\/ '{ sku: string; description<span class=\"hljs-doctag\">XXX:<\/span> string; originCodeXX<span class=\"hljs-doctag\">XXX:<\/span> string; }' but required in type 'InventoryItem'.<\/span>\n        originCodeXXXXX: item.item_origin_code,\n      } <span class=\"hljs-keyword\">as<\/span> InventoryItem;\n    })\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>TypeScript will allow you to lie, but only so far. If the cast makes absolutely no sense, TypeScript won&#8217;t allow it. As the error indicates, if you, for some reason, actually wanted to go through with this code, you could do:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"TypeScript\" data-shcb-language-slug=\"typescript\"><span><code class=\"hljs language-typescript\">&lt;code&gt;<span class=\"hljs-keyword\">as<\/span> unknown <span class=\"hljs-keyword\">as<\/span> InventoryItem;&lt;<span class=\"hljs-regexp\">\/code&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">TypeScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">typescript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>since <code>unknown<\/code> is a &#8220;top&#8221; type, which means anything can be cast to it, and from it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"wrapping-up\">Wrapping up<\/h2>\n\n\n\n<p>Use <code>satisfies<\/code> when you want to prevent <em>type<\/em> <em>widenings<\/em>, in situations where a top-level variable declaration doesn&#8217;t quite fit well.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The `satisfies` keyword allows you to assert that a certain value &#8220;satisfies&#8221; a given type, while preventing a wider type from being inferred.<\/p>\n","protected":false},"author":21,"featured_media":6454,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[363,184],"class_list":["post-6443","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-satisfies","tag-typescript"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/07\/Satisfies-in-TypeScript-v2.jpg?fit=1140%2C676&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/6443","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=6443"}],"version-history":[{"count":6,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/6443\/revisions"}],"predecessor-version":[{"id":6455,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/6443\/revisions\/6455"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/6454"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=6443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=6443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=6443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}