纳格兰天空树 發表於 2026-1-13 10:50:24

Typescript中infer关键字的使用小结

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">基本语法</a></li><li><a href="#_label1">主要使用场景</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">1.获取函数返回类型</a></li><li><a href="#_lab2_1_1">2.获取函数参数类型</a></li><li><a href="#_lab2_1_2">3.获取数组/元组元素类型</a></li><li><a href="#_lab2_1_3">4.获取 Promise 的解析类型</a></li></ul><li><a href="#_label2">实际应用示例</a></li><ul class="second_class_ul"><li><a href="#_lab2_2_4">示例1:提取对象值类型</a></li><li><a href="#_lab2_2_5">示例2:提取构造函数实例类型</a></li><li><a href="#_lab2_2_6">示例3:递归解包嵌套 Promise</a></li></ul><li><a href="#_label3">使用注意事项</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_7">1.只能用在条件类型的 extends 子句中</a></li><li><a href="#_lab2_3_8">2.多个 infer 可以同时使用</a></li><li><a href="#_lab2_3_9">3.协变位置 vs 逆变位置</a></li></ul><li><a href="#_label4">实战技巧</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_10">1.类型守卫与 infer</a></li><li><a href="#_lab2_4_11">2.构建实用类型工具</a></li></ul><li><a href="#_label5">总结</a></li><ul class="second_class_ul"></ul></ul></div><p><code>infer</code>&nbsp;是 TypeScript 中<strong>条件类型</strong>的一个关键字,主要用于<strong>在条件类型中进行类型推断</strong>。它允许我们在泛型条件类型中<strong>声明一个类型变量</strong>,然后从其他类型中<strong>推断出这个类型</strong>。</p>
<p class="maodian"><a name="_label0"></a></p><h2>基本语法</h2>
<div class="jb51code"><pre class="brush:js;">type ReturnType&lt;T&gt; = T extends (...args: any[]) =&gt; infer R ? R : never;
</pre></div>
<p class="maodian"><a name="_label1"></a></p><h2>主要使用场景</h2>
<p class="maodian"><a name="_lab2_1_0"></a></p><h3>1.获取函数返回类型</h3>
<div class="jb51code"><pre class="brush:js;">// 内置的 ReturnType 实现原理
type MyReturnType&lt;T&gt; = T extends (...args: any[]) =&gt; infer R ? R : never;

function foo(): string {
return "hello";
}

type FooReturn = MyReturnType&lt;typeof foo&gt;; // string
</pre></div>
<p class="maodian"><a name="_lab2_1_1"></a></p><h3>2.获取函数参数类型</h3>
<div class="jb51code"><pre class="brush:js;">// 获取第一个参数类型
type FirstParam&lt;T&gt; = T extends (first: infer P, ...rest: any[]) =&gt; any ? P : never;

// 获取所有参数类型(元组)
type Params&lt;T&gt; = T extends (...args: infer P) =&gt; any ? P : never;

function bar(x: number, y: string): void {}

type BarFirstParam = FirstParam&lt;typeof bar&gt;; // number
type BarParams = Params&lt;typeof bar&gt;; //
</pre></div>
<p class="maodian"><a name="_lab2_1_2"></a></p><h3>3.获取数组/元组元素类型</h3>
<p>typescript</p>
<div class="jb51code"><pre class="brush:js;">type ArrayElement&lt;T&gt; = T extends (infer U)[] ? U : never;

type StrArrayElement = ArrayElement&lt;string[]&gt;; // string
type NumArrayElement = ArrayElement&lt;number[]&gt;; // number
</pre></div>
<p class="maodian"><a name="_lab2_1_3"></a></p><h3>4.获取 Promise 的解析类型</h3>
<div class="jb51code"><pre class="brush:js;">type UnwrapPromise&lt;T&gt; = T extends Promise&lt;infer U&gt; ? U : T;

type PromiseString = Promise&lt;string&gt;;
type Unwrapped = UnwrapPromise&lt;PromiseString&gt;; // string
</pre></div>
<p class="maodian"><a name="_label2"></a></p><h2>实际应用示例</h2>
<p class="maodian"><a name="_lab2_2_4"></a></p><h3>示例1:提取对象值类型</h3>
<div class="jb51code"><pre class="brush:js;">type ValueOf&lt;T&gt; = T extends { : infer V } ? V : never;

type Obj = { a: number; b: string };
type Values = ValueOf&lt;Obj&gt;; // number | string
</pre></div>
<p class="maodian"><a name="_lab2_2_5"></a></p><h3>示例2:提取构造函数实例类型</h3>
<div class="jb51code"><pre class="brush:js;">type InstanceType&lt;T&gt; = T extends new (...args: any[]) =&gt; infer R ? R : any;

class Animal {
name: string;
constructor(name: string) {
    this.name = name;
}
}

type AnimalInstance = InstanceType&lt;typeof Animal&gt;; // Animal
</pre></div>
<p class="maodian"><a name="_lab2_2_6"></a></p><h3>示例3:递归解包嵌套 Promise</h3>
<div class="jb51code"><pre class="brush:js;">type DeepUnwrapPromise&lt;T&gt; =
T extends Promise&lt;infer U&gt; ? DeepUnwrapPromise&lt;U&gt; : T;

type NestedPromise = Promise&lt;Promise&lt;string&gt;&gt;;
type Result = DeepUnwrapPromise&lt;NestedPromise&gt;; // string
</pre></div>
<p class="maodian"><a name="_label3"></a></p><h2>使用注意事项</h2>
<p class="maodian"><a name="_lab2_3_7"></a></p><h3>1.只能用在条件类型的 extends 子句中</h3>
<div class="jb51code"><pre class="brush:js;">// ✅ 正确
type Example1&lt;T&gt; = T extends Array&lt;infer U&gt; ? U : never;

// ❌ 错误:infer 不能单独使用
type Example2&lt;T&gt; = infer U; // 编译错误
</pre></div>
<p class="maodian"><a name="_lab2_3_8"></a></p><h3>2.多个 infer 可以同时使用</h3>
<div class="jb51code"><pre class="brush:js;">type Zip&lt;T, U&gt; = T extends
? U extends
    ? [, ...Zip&lt;RestT, RestU&gt;]
    : []
: [];

type Result = Zip&lt;, ['a', 'b']&gt;; // [, ]
</pre></div>
<p class="maodian"><a name="_lab2_3_9"></a></p><h3>3.协变位置 vs 逆变位置</h3>
<div class="jb51code"><pre class="brush:js;">// infer 在协变位置(返回类型)
type GetReturnType&lt;T&gt; = T extends () =&gt; infer R ? R : never;

// infer 在逆变位置(参数类型)
type GetArgType&lt;T&gt; = T extends (arg: infer A) =&gt; any ? A : never;
</pre></div>
<p class="maodian"><a name="_label4"></a></p><h2>实战技巧</h2>
<p class="maodian"><a name="_lab2_4_10"></a></p><h3>1.类型守卫与 infer</h3>
<div class="jb51code"><pre class="brush:js;">function isPromise&lt;T&gt;(value: any): value is Promise&lt;T&gt; {
return value &amp;&amp; typeof value.then === 'function';
}

async function handle&lt;T&gt;(input: T | Promise&lt;T&gt;): Promise&lt;T&gt; {
if (isPromise(input)) {
    // 这里 input 被推断为 Promise&lt;T&gt;
    return input;
}
return Promise.resolve(input);
}
</pre></div>
<p class="maodian"><a name="_lab2_4_11"></a></p><h3>2.构建实用类型工具</h3>
<div class="jb51code"><pre class="brush:js;">// 提取所有方法的返回类型
type MethodsReturnType&lt;T&gt; = {
: T extends (...args: any[]) =&gt; infer R ? R : never;
};

// 提取特定属性的类型
type PropType&lt;T, K extends keyof T&gt; = T extends { : infer V } ? V : never;
</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>总结</h2>
<p><code>infer</code>&nbsp;的核心作用:<strong>在条件类型中提取未知类型的内部结构</strong>。它是 TypeScript 类型系统的高级特性,常用于:</p>
<ol><li><strong>类型提取</strong>:从已有类型中提取部分类型信息</li><li><strong>类型转换</strong>:将一个类型转换为另一种形式</li><li><strong>类型推导</strong>:根据上下文推导出具体类型</li><li><strong>工具类型创建</strong>:构建复杂的实用类型工具</li></ol>
<p>掌握&nbsp;<code>infer</code>&nbsp;的关键是多实践,从简单的函数返回类型提取开始,逐步应用到更复杂的类型操作中。</p>
頁: [1]
查看完整版本: Typescript中infer关键字的使用小结