{"id":788,"date":"2025-08-19T21:34:49","date_gmt":"2025-08-20T03:34:49","guid":{"rendered":"https:\/\/kop.lat\/blog\/?p=788"},"modified":"2025-08-19T21:34:49","modified_gmt":"2025-08-20T03:34:49","slug":"infer-in-typescript","status":"publish","type":"post","link":"https:\/\/kop.lat\/blog\/infer-in-typescript\/","title":{"rendered":"infer in TypeScript"},"content":{"rendered":"\n<p><code>infer<\/code> in TypeScript \u2014 it\u2019s one of the most powerful(but sometimes confusing) features.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd0e What is <code>infer<\/code>?<\/h2>\n\n\n\n<p>The <code>infer<\/code> keyword is used <strong>inside a conditional type<\/strong> to <strong>declare a new type variable<\/strong> that TypeScript will try to &#8220;infer&#8221; (deduce) from the type expression.<\/p>\n\n\n\n<p>In plain words:<\/p>\n\n\n\n<ul>\n<li><strong><code>infer<\/code> = \u201clet TypeScript figure this type out here, and I\u2019ll give it a name so I can use it later.\u201d<\/strong><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u26a1 Syntax<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>T extends SomeType&lt;infer U&gt; ? U : Fallback\n<\/code><\/pre>\n\n\n\n<ul>\n<li>If <code>T<\/code> matches <code>SomeType&lt;...&gt;<\/code>, then TypeScript extracts the type inside and binds it to <code>U<\/code>.<\/li>\n\n\n\n<li>Otherwise, the fallback branch is used.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udccc Simple Examples<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Extracting an array element type<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>type ElementType&lt;T&gt; = T extends (infer U)&#91;] ? U : never;\n\ntype A = ElementType&lt;string&#91;]&gt;; \/\/ string\ntype B = ElementType&lt;number&#91;]&gt;; \/\/ number\ntype C = ElementType&lt;boolean&gt;;  \/\/ never (not an array)\n<\/code><\/pre>\n\n\n\n<p>Here, <code>infer U<\/code> captures the element type of the array.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">2. Extracting function return type<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>type MyReturnType&lt;T&gt; = T extends (...args: any&#91;]) =&gt; infer R ? R : never;\n\ntype A = MyReturnType&lt;() =&gt; number&gt;;     \/\/ number\ntype B = MyReturnType&lt;(x: string) =&gt; boolean&gt;; \/\/ boolean\ntype C = MyReturnType&lt;string&gt;;           \/\/ never\n<\/code><\/pre>\n\n\n\n<p>Here, <code>infer R<\/code> captures the return type of the function.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">3. Extracting function parameter type<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>type FirstArg&lt;T&gt; = T extends (arg: infer P, ...args: any&#91;]) =&gt; any ? P : never;\n\ntype A = FirstArg&lt;(x: string, y: number) =&gt; void&gt;; \/\/ string\ntype B = FirstArg&lt;() =&gt; void&gt;; \/\/ never\n<\/code><\/pre>\n\n\n\n<p>Here, <code>infer P<\/code> captures the type of the first parameter.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udde0 How it works under the hood<\/h2>\n\n\n\n<p>Think of <code>infer<\/code> like a <strong>pattern match for types<\/strong>:<\/p>\n\n\n\n<ul>\n<li><code>infer<\/code> only appears in a conditional type (<code>extends ? :<\/code>).<\/li>\n\n\n\n<li>When TypeScript sees <code>infer R<\/code>, it tries to <strong>unify<\/strong> the given type with the pattern, extracting what fits into <code>R<\/code>.<\/li>\n\n\n\n<li>If successful, you can use that inferred type in the true branch.<\/li>\n\n\n\n<li>If not, the false branch is chosen.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\ude80 Why is <code>infer<\/code> powerful?<\/h2>\n\n\n\n<p>Because you can <strong>extract pieces of types dynamically<\/strong>, without manually writing them.<br>This is how many utility types (like <code>ReturnType<\/code>, <code>Parameters<\/code>, <code>InstanceType<\/code>, etc.) are built.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\u2705 <strong>Summary of <code>infer<\/code>:<\/strong><\/p>\n\n\n\n<ul>\n<li>Used only in conditional types.<\/li>\n\n\n\n<li>Introduces a temporary type variable (<code>infer X<\/code>).<\/li>\n\n\n\n<li>TypeScript automatically deduces what <code>X<\/code> should be if the pattern matches.<\/li>\n\n\n\n<li>Lets you extract parts of complex types (array elements, function returns, parameters, etc.).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>Build your <strong>own custom utility types<\/strong> step by step using <code>infer<\/code> (like <code>Parameters&lt;T><\/code>, <code>ConstructorArgs&lt;T><\/code>, etc.) !<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>infer in TypeScript \u2014 it\u2019s one of the most powerful(but sometimes confusing) features. \ud83d\udd0e What is infer? The infer keyword is used inside a conditional type to declare a new type variable that TypeScript will try to &#8220;infer&#8221; (deduce) from the type expression. In plain words: \u26a1 Syntax \ud83d\udccc Simple Examples 1. Extracting an array [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":474,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[49],"tags":[23,63],"_links":{"self":[{"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/posts\/788"}],"collection":[{"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/comments?post=788"}],"version-history":[{"count":1,"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/posts\/788\/revisions"}],"predecessor-version":[{"id":789,"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/posts\/788\/revisions\/789"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/media\/474"}],"wp:attachment":[{"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/media?parent=788"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/categories?post=788"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kop.lat\/blog\/wp-json\/wp\/v2\/tags?post=788"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}